Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

7112 lines
180 KiB

/*++
Copyright (c) 1990-1994 Microsoft Corporation
Module Name:
videoprt.c
Abstract:
This is the NT Video port driver.
Author:
Andre Vachon (andreva) 18-Dec-1991
Environment:
kernel mode only
Notes:
This module is a driver which implements OS dependant functions on the
behalf of the video drivers
Revision History:
--*/
#include "dderror.h"
#include "ntos.h"
#include "pci.h"
#include "stdarg.h"
#include "stdio.h"
#include "zwapi.h"
#include "ntiologc.h"
#include "ntddvdeo.h"
#include "video.h"
// videoprt.h dummy:
#include "dma.h"
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,DriverEntry)
#pragma alloc_text(PAGE,VideoPortCompareMemory )
#pragma alloc_text(PAGE,pVideoPortDispatch)
#pragma alloc_text(PAGE,VideoPortFreeDeviceBase)
#pragma alloc_text(PAGE,pVideoPortFreeDeviceBase)
#pragma alloc_text(PAGE,VideoPortGetBusData)
#pragma alloc_text(PAGE,VideoPortGetCurrentIrql)
#pragma alloc_text(PAGE,pVideoPortGetDeviceBase)
#pragma alloc_text(PAGE,VideoPortGetDeviceBase)
#pragma alloc_text(PAGE,pVideoPortGetDeviceDataRegistry)
#pragma alloc_text(PAGE,VideoPortGetDeviceData)
#pragma alloc_text(PAGE,pVideoPortGetRegistryCallback)
#pragma alloc_text(PAGE,VideoPortGetRegistryParameters)
#pragma alloc_text(PAGE,pVPInit)
#pragma alloc_text(PAGE,pVideoPortInitializeBusCallback)
#pragma alloc_text(PAGE,pVideoPorInitializeDebugCallback)
#pragma alloc_text(PAGE,VideoPortInitialize)
#pragma alloc_text(PAGE,pVideoPortMapToNtStatus)
#pragma alloc_text(PAGE,pVideoPortMapUserPhysicalMem)
#pragma alloc_text(PAGE,VideoPortMapMemory)
#pragma alloc_text(PAGE,VideoPortMapBankedMemory)
#pragma alloc_text(PAGE,VideoPortScanRom)
#pragma alloc_text(PAGE,VideoPortSetBusData)
#pragma alloc_text(PAGE,VideoPortSetRegistryParameters)
#pragma alloc_text(PAGE,VideoPortUnmapMemory)
#endif
//
// Debug variable for error messages
//
BOOLEAN VPFirstTime = TRUE;
#if DBG
BOOLEAN VPResourcesReported = FALSE;
BOOLEAN VPInitPhase = FALSE;
#endif
//
// Debug Level for output routine
//
ULONG VideoDebugLevel = 0;
//
// Count to determine the number of video devices
//
ULONG VideoDeviceNumber = 0;
//
// Registry Class in which all video information is stored.
//
PWSTR VideoClassString = L"VIDEO";
UNICODE_STRING VideoClassName = {10,12,L"VIDEO"};
//
// Global variables used to keep track of where controllers or peripherals
// are found by IoQueryDeviceDescription
//
CONFIGURATION_TYPE VpQueryDeviceControllerType = DisplayController;
CONFIGURATION_TYPE VpQueryDevicePeripheralType = MonitorPeripheral;
ULONG VpQueryDeviceControllerNumber;
ULONG VpQueryDevicePeripheralNumber;
//
// Globals to support HwResetHw function
//
VP_RESET_HW HwResetHw[6];
PVP_RESET_HW HwResetHwPointer;
//
// Global used to determine if we are running in BASEVIDEO mode.
//
// If we are, we don't want to generate a conflict for the VGA driver resources
// if there is one.
// We also want to write a volatile key in the registry indicating we booted
// in beasevideo so the display driver loading code can handle it properly
//
BOOLEAN VpBaseVideo = FALSE;
//
// Variable used to so int10 support.
//
PEPROCESS CsrProcess = NULL;
//
// Variable to determine if there is a ROM at physical address C0000 on which
// we can do the int 10
//
ULONG VpC0000Compatible = 0;
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
/*++
Routine Description:
Temporary entry point needed to initialize the video port driver.
Arguments:
DriverObject - Pointer to the driver object created by the system.
Return Value:
STATUS_SUCCESS
--*/
{
UNREFERENCED_PARAMETER(DriverObject);
//
//
//
// WARNING !!!
//
// This function is never called because we are loaded as a DLL by other video drivers !
//
//
//
//
//
//
// We always return STATUS_SUCCESS because otherwise no video miniport
// driver will be able to call us.
//
return STATUS_SUCCESS;
} // end DriverEntry()
//
//ULONG
//VideoPortCompareMemory (
// PVOID Source1,
// PVOID Source2,
// ULONG Length
// )
//Forwarded to RtlCompareMemory(Source1,Source2,Length);
//
VOID
VideoPortDebugPrint(
ULONG DebugPrintLevel,
PCHAR DebugMessage,
...
)
/*++
Routine Description:
This routine allows the miniport drivers (as well as the port driver) to
display error messages to the debug port when running in the debug
environment.
When running a non-debugged system, all references to this call are
eliminated by the compiler.
Arguments:
DebugPrintLevel - Debug print level between 0 and 3, with 3 being the
most verbose.
Return Value:
None.
--*/
{
va_list ap;
va_start(ap, DebugMessage);
if (DebugPrintLevel <= VideoDebugLevel) {
char buffer[256];
vsprintf(buffer, DebugMessage, ap);
DbgPrint(buffer);
}
va_end(ap);
} // VideoPortDebugPrint()
VP_STATUS
VideoPortDisableInterrupt(
IN PVOID HwDeviceExtension
)
/*++
Routine Description:
VideoPortDisableInterrupt allows a miniport driver to disable interrupts
from its adapter. This means that the interrupts coming from the device
will be ignored by the operating system and therefore not forwarded to
the driver.
A call to this function is valid only if the interrupt is defined, in
other words, if the appropriate data was provided at initialization
time to set up the interrupt. Interrupts will remain disabled until
they are reenabled using the VideoPortEnableInterrupt function.
Arguments:
HwDeviceExtension - Points to the miniport driver's device extension.
Return Value:
NO_ERROR if the function completes successfully.
ERROR_INVALID_FUNCTION if the interrupt cannot be disabled because it
was not set up at initialization.
--*/
{
PDEVICE_EXTENSION deviceExtension =
((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
//
// Only perform this operation if the interurpt is actually connected.
//
if (deviceExtension->InterruptObject) {
HalDisableSystemInterrupt(deviceExtension->InterruptVector,
deviceExtension->InterruptIrql);
return NO_ERROR;
} else {
return ERROR_INVALID_FUNCTION;
}
} // VideoPortDisableInterrupt()
NTSTATUS
pVideoPortDispatch(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine is the main dispatch routine for the video port driver.
It accepts an I/O Request Packet, transforms it to a video Request
Packet, and forwards it to the appropriate miniport dispatch routine.
Upon returning, it completes the request and return the appropriate
status value.
Arguments:
DeviceObject - Pointer to the device object of the miniport driver to
which the request must be sent.
Irp - Pointer to the request packet representing the I/O request.
Return Value:
The function value os the status of the operation.
--*/
{
PDEVICE_EXTENSION deviceExtension;
PIO_STACK_LOCATION irpStack;
PVOID ioBuffer;
ULONG inputBufferLength;
ULONG outputBufferLength;
PSTATUS_BLOCK statusBlock;
NTSTATUS finalStatus;
ULONG ioControlCode;
VIDEO_DMA_REQUEST_BLOCK vdrb;
//
// Get pointer to the port driver's device extension.
//
deviceExtension = DeviceObject->DeviceExtension;
//
// Get a pointer to the current location in the Irp. This is where
// the function codes and parameters are located.
//
irpStack = IoGetCurrentIrpStackLocation(Irp);
//
// Get the pointer to the status buffer
//
statusBlock = (PSTATUS_BLOCK) &Irp->IoStatus;
//
// Get the pointer to the input/output buffer and it's length
//
ioBuffer = Irp->AssociatedIrp.SystemBuffer;
inputBufferLength =
irpStack->Parameters.DeviceIoControl.InputBufferLength;
outputBufferLength =
irpStack->Parameters.DeviceIoControl.OutputBufferLength;
//
// Synchronize execution of the dispatch routine by acquiring the device
// event object. This ensures all request are serialized.
// The synchronization must be done explicitly because the functions
// executed in the dispatch routine use system services that cannot
// be executed in the start I/O routine.
//
// The synchronization is done on the miniport's event so as not to
// block commands coming in for another device.
//
KeWaitForSingleObject(&deviceExtension->SyncEvent,
Executive,
KernelMode,
FALSE,
(PTIME)NULL);
//
// Save the requestor mode in the DeviceExtension
//
deviceExtension->CurrentIrpRequestorMode = Irp->RequestorMode;
//
// Assume success for now.
//
statusBlock->Status = STATUS_SUCCESS;
//
// Case on the function being requested.
// If the function is operating specific, intercept the operation and
// perform directly. Otherwise, pass it on to the appropriate miniport.
//
switch (irpStack->MajorFunction) {
//
// Called by the display driver *or a user-mode application*
// to get exclusive access to the device.
// This access is given by the I/O system (based on a bit set during the
// IoCreateDevice() call).
//
case IRP_MJ_CREATE:
pVideoDebugPrint((2, "VideoPort - CREATE\n"));
//
// Special hack to succeed on Attach, but not do anything ...
// That way on the close caused by the attach we will not actually
// close the device and screw the HAL.
//
if (irpStack->Parameters.Create.SecurityContext->DesiredAccess ==
FILE_READ_ATTRIBUTES) {
statusBlock->Information = FILE_OPEN;
statusBlock->Status = STATUS_SUCCESS;
deviceExtension->bAttachInProgress = TRUE;
break;
}
//
// Tell the HAL we are now reinitializing the device.
//
HalAcquireDisplayOwnership(pVideoPortResetDisplay);
//
// Now perform basic initialization to allow the Windows display
// driver to set up the device appropriately.
//
statusBlock->Information = FILE_OPEN;
//
// We will need to attach to the CSR process to do an int 10.
// Save the value of that process so we can do an attach later on.
//
#if defined(_X86_)
//
// Only on X86 do we use CSR to do the modeset.
// So its the only architecture on which we have to attach to the
// CSR process.
//
if (CsrProcess == NULL)
{
CsrProcess = PsGetCurrentProcess();
}
#endif
#if DBG
//
// Turn off checking for mapped address since we are not in find
// adapter ever again.
//
VPInitPhase = TRUE;
VPResourcesReported = TRUE;
#endif
//
// Initialize the device.
//
if (!(BOOLEAN)deviceExtension->HwInitialize(
deviceExtension->HwDeviceExtension)) {
statusBlock->Status = STATUS_UNSUCCESSFUL;
pVideoDebugPrint((1, "VideoPortDispatch: Can not initialize video device\n"));
}
break;
//
// Called when the display driver wishes to give up it's handle to the
// device.
//
case IRP_MJ_CLOSE:
pVideoDebugPrint((2, "Videoprt - CLOSE\n"));
//
// Special hack to succeed on Attach, but not do anything ...
// That way on the close caused by the attach we will not actually
// close the device and screw the HAL.
//
if (deviceExtension->bAttachInProgress == TRUE) {
deviceExtension->bAttachInProgress = FALSE;
statusBlock->Status = STATUS_SUCCESS;
break;
}
vdrb.vrp.IoControlCode = IOCTL_VIDEO_RESET_DEVICE;
vdrb.vrp.StatusBlock = statusBlock;
vdrb.vrp.InputBuffer = NULL;
vdrb.vrp.InputBufferLength = 0;
vdrb.vrp.OutputBuffer = NULL;
vdrb.vrp.OutputBufferLength = 0;
vdrb.vrp.bUnlock = FALSE;
//
// Send the request to the miniport.
//
deviceExtension->HwStartIO(deviceExtension->HwDeviceExtension,
&(vdrb.vrp));
//
// Override error from the miniport and return success.
//
statusBlock->Status = STATUS_SUCCESS;
break;
//
// Device Controls are specific functions for the driver.
// First check for calls that must be intercepted and hidden from the
// miniport driver. These calls are hidden for simplicity.
// The other control functions are passed down to the miniport after
// the request structure has been filled out properly.
//
case IRP_MJ_DEVICE_CONTROL:
ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
if (ioControlCode == IOCTL_VIDEO_DMA_INIT ||
ioControlCode == IOCTL_VIDEO_DMA_TRANSFER ||
ioControlCode == IOCTL_VIDEO_DMA_UNLOCK_PAGES) {
//
// Make sure the MdlAddress in the Irp is NULL, otherwise
// IoCompleteRequest tries to free it.
//
Irp->MdlAddress = NULL;
vdrb.pDma = NULL;
if (ioControlCode == IOCTL_VIDEO_DMA_TRANSFER) {
vdrb.pDma = ioBuffer;
}
}
//
// Enabling or disabling the VDM is done only by the port driver.
//
if (ioControlCode == IOCTL_VIDEO_REGISTER_VDM) {
pVideoDebugPrint((2, "VideoPort - RegisterVdm\n"));
statusBlock->Status = pVideoPortRegisterVDM(deviceExtension,
(PVIDEO_VDM) ioBuffer,
inputBufferLength,
(PVIDEO_REGISTER_VDM) ioBuffer,
outputBufferLength,
&statusBlock->Information);
} else if (ioControlCode == IOCTL_VIDEO_DISABLE_VDM) {
pVideoDebugPrint((2, "VideoPort - DisableVdm\n"));
statusBlock->Status = pVideoPortEnableVDM(deviceExtension,
FALSE,
(PVIDEO_VDM) ioBuffer,
inputBufferLength);
} else if (ioControlCode == IOCTL_VIDEO_DMA_UNLOCK_PAGES) {
PDMA_PARAMETERS pIoVrb = pVideoPortGetIoVrbData(deviceExtension, &vdrb);
pVideoDebugPrint((VIDEO_DMA_LOCK,
"IOCTL_VIDEO_DMA_UNLOCK_PAGES: Got PDMA:%x from pVDRBB:%x\n",
pIoVrb, &vdrb));
pVideoDebugPrint((VIDEO_DMA_LOCK, "ioControlCode:%x\n", ioControlCode));
pIoVrb->pVideoRequestBlock->pDma = pIoVrb;
vdrb.vrp.bUnlock = TRUE;
vdrb.vrp.IoControlCode = ioControlCode;
statusBlock->Status = pVideoDmaProcessCompletedRequest(deviceExtension, pIoVrb);
} else {
//
// All other request need to be passed to the miniport driver.
//
switch (ioControlCode) {
case IOCTL_VIDEO_ENABLE_VDM:
pVideoDebugPrint((2, "VideoPort - EnableVdm\n"));
statusBlock->Status = pVideoPortEnableVDM(deviceExtension,
TRUE,
(PVIDEO_VDM) ioBuffer,
inputBufferLength);
#if DBG
if (statusBlock->Status == STATUS_CONFLICTING_ADDRESSES) {
ASSERT(FALSE);
}
#endif
break;
case IOCTL_VIDEO_SAVE_HARDWARE_STATE:
pVideoDebugPrint((2, "VideoPort - SaveHardwareState\n"));
//
// allocate the memory required by the miniport driver so it can
// save its state to be returned to the caller.
//
if (deviceExtension->HardwareStateSize == 0) {
statusBlock->Status = STATUS_NOT_IMPLEMENTED;
break;
}
//
// Must make sure the caller is a trusted subsystem with the
// appropriate privilege level before executing this call.
// If the calls returns FALSE we must return an error code.
//
if (!SeSinglePrivilegeCheck(RtlConvertLongToLuid(
SE_TCB_PRIVILEGE),
deviceExtension->CurrentIrpRequestorMode)) {
statusBlock->Status = STATUS_PRIVILEGE_NOT_HELD;
break;
}
((PVIDEO_HARDWARE_STATE)(ioBuffer))->StateLength =
deviceExtension->HardwareStateSize;
statusBlock->Status =
ZwAllocateVirtualMemory(NtCurrentProcess(),
(PVOID *) &(((PVIDEO_HARDWARE_STATE)(ioBuffer))->StateHeader),
0L,
&((PVIDEO_HARDWARE_STATE)(ioBuffer))->StateLength,
MEM_COMMIT,
PAGE_READWRITE);
break;
case IOCTL_VIDEO_QUERY_PUBLIC_ACCESS_RANGES:
pVideoDebugPrint((2, "VideoPort - QueryAccessRanges\n"));
//
// Must make sure the caller is a trusted subsystem with the
// appropriate privilege level before executing this call.
// If the calls returns FALSE we must return an error code.
//
if (!SeSinglePrivilegeCheck(RtlConvertLongToLuid(
SE_TCB_PRIVILEGE),
deviceExtension->CurrentIrpRequestorMode)) {
statusBlock->Status = STATUS_PRIVILEGE_NOT_HELD;
}
break;
//
// The default case is when the port driver does not handle the
// request. We must then call the miniport driver.
//
default:
break;
} // switch (ioControlCode)
//
// All above cases call the miniport driver.
//
// only process it if no errors happened in the port driver
// processing.
//
if (NT_SUCCESS(statusBlock->Status)) {
pVideoDebugPrint((2, "VideoPort - default function\n"));
vdrb.vrp.IoControlCode = ioControlCode;
vdrb.vrp.StatusBlock = statusBlock;
vdrb.vrp.InputBuffer = ioBuffer;
vdrb.vrp.InputBufferLength = inputBufferLength;
vdrb.vrp.OutputBuffer = ioBuffer;
vdrb.vrp.OutputBufferLength = outputBufferLength;
//
// Send the request to the miniport.
//
deviceExtension->HwStartIO(deviceExtension->HwDeviceExtension,
&(vdrb.vrp));
if (statusBlock->Status != NO_ERROR) {
//
// Make sure we don't tell the IO system to copy data
// on a real error.
//
if (statusBlock->Status != ERROR_MORE_DATA) {
ASSERT(statusBlock->Information == 0);
statusBlock->Information = 0;
}
pVideoPortMapToNtStatus(statusBlock);
//
// !!! Compatibility:
// Do not require a miniport to support the REGISTER_VDM
// IOCTL, so if we get an error in that case, just
// return success.
//
// Do put up a message so people fix this.
//
if (ioControlCode == IOCTL_VIDEO_ENABLE_VDM) {
statusBlock->Status = STATUS_SUCCESS;
pVideoDebugPrint((0, "VIDEO PORT: The video miniport driver does not support the IOCTL_VIDEO_ENABLE_VDM function. The video miniport driver *should* be fixed. \n"));
}
}
}
} // if (ioControlCode == ...
break;
//
// Other major entry points in the dispatch routine are not supported.
//
default:
break;
} // switch (irpStack->MajorFunction)
//
// save the final status so we can return it after the IRP is completed.
//
finalStatus = statusBlock->Status;
KeSetEvent(&deviceExtension->SyncEvent,
0,
FALSE);
pVideoDebugPrint((2, "Dispatch: calling IoCompleteRequest with Irp %x\n", Irp));
IoCompleteRequest(Irp,
IO_VIDEO_INCREMENT);
//
// We never have pending operation so always return the status code.
//
pVideoDebugPrint((2, "VideoPort: final IOCTL status: %08lx\n",
finalStatus));
return finalStatus;
} // pVideoPortDispatch()
VP_STATUS
VideoPortEnableInterrupt(
IN PVOID HwDeviceExtension
)
/*++
Routine Description:
VideoPortEnableInterrupt allows a miniport driver to enable interrupts
from its adapter. A call to this function is valid only if the
interrupt is defined, in other words, if the appropriate data was
provided at initialization time to set up the interrupt.
This function is used to re-enable interrupts if they have been disabled
using VideoPortDisableInterrupt.
Arguments:
HwDeviceExtension - Points to the miniport driver's device extension.
Return Value:
NO_ERROR if the function completes successfully.
ERROR_INVALID_FUNCTION if the interrupt cannot be disabled because it
was not set up at initialization.
--*/
{
PDEVICE_EXTENSION deviceExtension =
((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
//
// Only perform this operation if the interurpt is actually connected.
//
if (deviceExtension->InterruptObject) {
HalEnableSystemInterrupt(deviceExtension->InterruptVector,
deviceExtension->InterruptIrql,
deviceExtension->InterruptMode);
return NO_ERROR;
} else {
return ERROR_INVALID_FUNCTION;
}
} // VideoPortEnableInterrupt()
VOID
VideoPortFreeDeviceBase(
IN PVOID HwDeviceExtension,
IN PVOID MappedAddress
)
/*++
Routine Description:
VideoPortFreeDeviceBase frees a block of I/O addresses or memory space
previously mapped into the system address space by calling
VideoPortGetDeviceBase.
Arguments:
HwDeviceExtension - Points to the miniport driver's device extension.
MappedAddress - Specifies the base address of the block to be freed. This
value must be the same as the value returned by VideoPortGetDeviceBase.
Return Value:
None.
Environment:
This routine cannot be called from a miniport routine synchronized with
VideoPortSynchronizeRoutine or from an ISR.
--*/
{
pVideoPortFreeDeviceBase(HwDeviceExtension, MappedAddress);
return;
}
PVOID
pVideoPortFreeDeviceBase(
IN PVOID HwDeviceExtension,
IN PVOID MappedAddress
)
{
PDEVICE_EXTENSION deviceExtension;
PMAPPED_ADDRESS nextMappedAddress;
PMAPPED_ADDRESS lastMappedAddress;
deviceExtension = ((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
pVideoDebugPrint((2, "VPFreeDeviceBase at mapped address is %08lx\n",
MappedAddress));
nextMappedAddress = deviceExtension->MappedAddressList;
lastMappedAddress = deviceExtension->MappedAddressList;
while (nextMappedAddress) {
if (nextMappedAddress->MappedAddress == MappedAddress) {
//
// Count up how much memory a miniport driver is really taking
//
if (nextMappedAddress->bNeedsUnmapping) {
deviceExtension->MemoryPTEUsage -=
COMPUTE_PAGES_SPANNED(nextMappedAddress->MappedAddress,
nextMappedAddress->NumberOfUchars);
}
//
// BUGBUG use reference count temporarily since ATI maps too
// large a buffer to do two maps of it.
//
if (!(--nextMappedAddress->RefCount)) {
//
// Unmap address, if necessary.
//
if (nextMappedAddress->bNeedsUnmapping) {
if (nextMappedAddress->bLargePageRequest) {
MmUnmapVideoDisplay(nextMappedAddress->MappedAddress,
nextMappedAddress->NumberOfUchars);
} else {
MmUnmapIoSpace(nextMappedAddress->MappedAddress,
nextMappedAddress->NumberOfUchars);
}
}
//
// Remove mapped address from list.
//
if (lastMappedAddress == deviceExtension->MappedAddressList) {
deviceExtension->MappedAddressList =
nextMappedAddress->NextMappedAddress;
} else {
lastMappedAddress->NextMappedAddress =
nextMappedAddress->NextMappedAddress;
}
ExFreePool(nextMappedAddress);
}
//
// We just return the value to show that the call succeeded.
//
return (nextMappedAddress);
} else {
lastMappedAddress = nextMappedAddress;
nextMappedAddress = nextMappedAddress->NextMappedAddress;
}
}
return NULL;
} // end VideoPortFreeDeviceBase()
ULONG
VideoPortGetBusData(
PVOID HwDeviceExtension,
IN BUS_DATA_TYPE BusDataType,
IN ULONG SlotNumber,
IN PVOID Buffer,
IN ULONG Offset,
IN ULONG Length
)
{
PDEVICE_EXTENSION deviceExtension =
deviceExtension = ((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
//
// Issue a warning telling the miniport they should not read everything
// out of the driver config space otherwise it causes some device like
// NCR SCSIs to crash.
//
#if DBG
if ((BusDataType == PCIConfiguration) &&
(Length >= sizeof(PCI_COMMON_CONFIG)))
{
pVideoDebugPrint((0, "A miniport must only call VideoPortGetBusData with PCI_COMMON_HDR_LENGTH\n"));
DbgBreakPoint();
}
#endif
return HalGetBusDataByOffset(BusDataType,
deviceExtension->SystemIoBusNumber,
SlotNumber,
Buffer,
Offset,
Length);
} // end VideoPortGetBusData()
UCHAR
VideoPortGetCurrentIrql(
)
/*++
Routine Description:
Stub to get Current Irql.
--*/
{
return (KeGetCurrentIrql());
} // VideoPortGetCurrentIrql()
PVOID
VideoPortGetDeviceBase(
IN PVOID HwDeviceExtension,
IN PHYSICAL_ADDRESS IoAddress,
IN ULONG NumberOfUchars,
IN UCHAR InIoSpace
)
/*++
Routine Description:
VideoPortGetDeviceBase maps a memory or I/O address range into the
system (kernel) address space. Access to this mapped address space
must follow these rules:
If the input value for InIoSpace is 1 (the address IS in I/O space),
the returned logical address should be used in conjunction with
VideoPort[Read/Write]Port[Uchar/Ushort/Ulong] functions.
^^^^
If the input value for InIoSpace is 0 (the address IS NOT in I/O
space), the returned logical address should be used in conjunction
with VideoPort[Read/Write]Register[Uchar/Ushort/Ulong] functions.
^^^^^^^^
Note that VideoPortFreeDeviceBase is used to unmap a previously mapped
range from the system address space.
Arguments:
HwDeviceExtension - Points to the miniport driver's device extension.
IoAddress - Specifies the base physical address of the range to be
mapped in the system address space.
NumberOfUchars - Specifies the number of bytes, starting at the base
address, to map in system space. The driver must not access
addresses outside this range.
InIoSpace - Specifies that the address is in the I/O space if 1.
Otherwise, the address is assumed to be in memory space.
Return Value:
This function returns a base address suitable for use by the hardware
access functions. VideoPortGetDeviceBase may be called several times
by the miniport driver.
Environment:
This routine cannot be called from a miniport routine synchronized with
VideoPortSynchronizeRoutine or from an ISR.
--*/
{
//
// We specify large page as FALSE for the default since the miniport could
// be using the address at raise IRQL in an ISR.
//
return pVideoPortGetDeviceBase(HwDeviceExtension,
IoAddress,
NumberOfUchars,
InIoSpace,
FALSE);
}
PVOID
pVideoPortGetDeviceBase(
IN PVOID HwDeviceExtension,
IN PHYSICAL_ADDRESS IoAddress,
IN ULONG NumberOfUchars,
IN UCHAR InIoSpace,
IN BOOLEAN bLargePage
)
{
PDEVICE_EXTENSION deviceExtension =
deviceExtension = ((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
PHYSICAL_ADDRESS cardAddress;
PVOID mappedAddress = NULL;
PMAPPED_ADDRESS newMappedAddress;
BOOLEAN b;
ULONG addressSpace;
ULONG p6Caching = FALSE;
pVideoDebugPrint((2, "VPGetDeviceBase reqested %08lx mem type. address is %08lx %08lx, length of %08lx\n",
InIoSpace, IoAddress.HighPart, IoAddress.LowPart, NumberOfUchars));
//
// Properly configure the flags for translation
//
addressSpace = InIoSpace & 0xFF;
#if defined(_X86_)
//
// On X86, determine if we will want to map the memory with the
// special caching flag.
//
p6Caching = addressSpace & VIDEO_MEMORY_SPACE_P6CACHE;
#endif
addressSpace &= ~VIDEO_MEMORY_SPACE_P6CACHE;
#if !defined(_ALPHA_)
//
// On non-alpha, this does'nt mean anything
//
addressSpace &= ~VIDEO_MEMORY_SPACE_DENSE;
#endif
if (addressSpace & VIDEO_MEMORY_SPACE_USER_MODE) {
ASSERT(FALSE);
return NULL;
}
if (HalTranslateBusAddress(deviceExtension->AdapterInterfaceType,
deviceExtension->SystemIoBusNumber,
IoAddress,
&addressSpace,
&cardAddress)) {
//
// Use reference counting for addresses to support broken ATI !
// Return the previously mapped address if we find the same physical
// address.
//
PMAPPED_ADDRESS nextMappedAddress;
PMAPPED_ADDRESS lastMappedAddress;
pVideoDebugPrint((2, "VPGetDeviceBase requested %08lx mem type. physical address is %08lx %08lx, length of %08lx\n",
addressSpace, cardAddress.HighPart, cardAddress.LowPart, NumberOfUchars));
nextMappedAddress = deviceExtension->MappedAddressList;
lastMappedAddress = deviceExtension->MappedAddressList;
while (nextMappedAddress) {
if ((nextMappedAddress->bLargePageRequest == bLargePage) &&
(nextMappedAddress->NumberOfUchars == NumberOfUchars) &&
(nextMappedAddress->PhysicalAddress.QuadPart == cardAddress.QuadPart)) {
pVideoDebugPrint((0, "VPGetDeviceBase : refCount hit on address %08lx \n",
nextMappedAddress->PhysicalAddress.LowPart));
nextMappedAddress->RefCount++;
//
// Count up how much memory a miniport driver is really taking
//
if (nextMappedAddress->bNeedsUnmapping) {
deviceExtension->MemoryPTEUsage +=
COMPUTE_PAGES_SPANNED(nextMappedAddress->MappedAddress,
nextMappedAddress->NumberOfUchars);
}
return (nextMappedAddress->MappedAddress);
} else {
lastMappedAddress = nextMappedAddress;
nextMappedAddress = nextMappedAddress->NextMappedAddress;
}
}
//
// If the address is in IO space, don't do anything.
// If the address is in memory space, map it and save the information.
//
if (addressSpace & VIDEO_MEMORY_SPACE_IO) {
mappedAddress = (PVOID) cardAddress.LowPart;
b = FALSE;
} else {
//
// Map the device base address into the virtual address space
//
if (p6Caching) {
mappedAddress = MmMapIoSpace(cardAddress,
NumberOfUchars,
MmFrameBufferCached);
} else if (bLargePage) {
mappedAddress = MmMapVideoDisplay(cardAddress,
NumberOfUchars,
0);
} else {
mappedAddress = MmMapIoSpace(cardAddress,
NumberOfUchars,
FALSE);
}
if (mappedAddress == NULL) {
//
// A failiure occured
// BUGBUG we should log an error here !
//
pVideoDebugPrint((0, "VideoPort: MmMapIoSpace FAILED !!!\n"));
return NULL;
}
b = TRUE;
deviceExtension->MemoryPTEUsage +=
COMPUTE_PAGES_SPANNED(mappedAddress,
NumberOfUchars);
}
//
// Allocate memory to store mapped address for unmap.
//
newMappedAddress = ExAllocatePoolWithTag(NonPagedPool,
sizeof(MAPPED_ADDRESS),
'trpV');
//
// Save the reference if we can allocate memory for it. If we can
// not, just don't save it ... it's not a big deal.
//
if (newMappedAddress) {
//
// Store mapped address information.
//
newMappedAddress->PhysicalAddress = cardAddress;
newMappedAddress->RefCount = 1;
newMappedAddress->MappedAddress = mappedAddress;
newMappedAddress->NumberOfUchars = NumberOfUchars;
newMappedAddress->bNeedsUnmapping = b;
newMappedAddress->bLargePageRequest = bLargePage;
//
// Link current list to new entry.
//
newMappedAddress->NextMappedAddress =
deviceExtension->MappedAddressList;
//
// Point anchor at new list.
//
deviceExtension->MappedAddressList = newMappedAddress;
}
} else {
pVideoDebugPrint((1, "HALTranslateBusAddress failed !!\n"));
}
pVideoDebugPrint((2, "VPGetDeviceBase mapped virtual address is %08lx\n",
mappedAddress));
return mappedAddress;
} // end VideoPortGetDeviceBase()
NTSTATUS
pVideoPortGetDeviceDataRegistry(
IN PVOID Context,
IN PUNICODE_STRING PathName,
IN INTERFACE_TYPE BusType,
IN ULONG BusNumber,
IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
IN CONFIGURATION_TYPE ControllerType,
IN ULONG ControllerNumber,
IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
IN CONFIGURATION_TYPE PeripheralType,
IN ULONG PeripheralNumber,
IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
)
/*++
Routine Description:
Arguments:
Return Value:
Environment:
This routine cannot be called from a miniport routine synchronized with
VideoPortSynchronizeRoutine or from an ISR.
--*/
{
//
// This macro should be in the io system header file.
//
#define GetIoQueryDeviceInfo(DeviceInfo, InfoType) \
((PVOID) ( ((PUCHAR) (*(DeviceInfo + InfoType))) + \
((ULONG) (*(DeviceInfo + InfoType))->DataOffset) ))
#define GetIoQueryDeviceInfoLength(DeviceInfo, InfoType) \
((ULONG) (*(DeviceInfo + InfoType))->DataLength)
PVP_QUERY_DEVICE queryDevice = Context;
PKEY_VALUE_FULL_INFORMATION *deviceInformation;
PCM_FULL_RESOURCE_DESCRIPTOR configurationData;
switch (queryDevice->DeviceDataType) {
case VpBusData:
pVideoDebugPrint((2, "VPGetDeviceDataCallback BusData\n"));
configurationData = (PCM_FULL_RESOURCE_DESCRIPTOR)
GetIoQueryDeviceInfo(BusInformation,
IoQueryDeviceConfigurationData);
pVideoDebugPrint((2, "VPGetDeviceDataCallback BusData\n"));
if (NO_ERROR == ((PMINIPORT_QUERY_DEVICE_ROUTINE)
queryDevice->CallbackRoutine)(
queryDevice->MiniportHwDeviceExtension,
queryDevice->MiniportContext,
queryDevice->DeviceDataType,
GetIoQueryDeviceInfo(BusInformation,
IoQueryDeviceIdentifier),
GetIoQueryDeviceInfoLength(BusInformation,
IoQueryDeviceIdentifier),
(PVOID) &(configurationData->PartialResourceList.PartialDescriptors[1]),
configurationData->PartialResourceList.PartialDescriptors[0].u.DeviceSpecificData.DataSize,
GetIoQueryDeviceInfo(BusInformation,
IoQueryDeviceComponentInformation),
GetIoQueryDeviceInfoLength(BusInformation,
IoQueryDeviceComponentInformation)
)) {
return STATUS_SUCCESS;
} else {
return STATUS_DEVICE_DOES_NOT_EXIST;
}
break;
case VpControllerData:
deviceInformation = ControllerInformation;
pVideoDebugPrint((2, "VPGetDeviceDataCallback ControllerData\n"));
//
// This data we are getting is actually a CM_FULL_RESOURCE_DESCRIPTOR.
//
//
// BUGBUG save the error from the miniport ??
//
if (NO_ERROR == ((PMINIPORT_QUERY_DEVICE_ROUTINE)
queryDevice->CallbackRoutine)(
queryDevice->MiniportHwDeviceExtension,
queryDevice->MiniportContext,
queryDevice->DeviceDataType,
GetIoQueryDeviceInfo(deviceInformation,
IoQueryDeviceIdentifier),
GetIoQueryDeviceInfoLength(deviceInformation,
IoQueryDeviceIdentifier),
GetIoQueryDeviceInfo(deviceInformation,
IoQueryDeviceConfigurationData),
GetIoQueryDeviceInfoLength(deviceInformation,
IoQueryDeviceConfigurationData),
GetIoQueryDeviceInfo(deviceInformation,
IoQueryDeviceComponentInformation),
GetIoQueryDeviceInfoLength(deviceInformation,
IoQueryDeviceComponentInformation)
)) {
return STATUS_SUCCESS;
} else {
return STATUS_DEVICE_DOES_NOT_EXIST;
}
break;
case VpMonitorData:
deviceInformation = PeripheralInformation;
pVideoDebugPrint((2, "VPGetDeviceDataCallback MonitorData\n"));
//
// This data we are getting is actually a CM_FULL_RESOURCE_DESCRIPTOR.
//
//
// BUGBUG save the error from the miniport ??
//
if (NO_ERROR == ((PMINIPORT_QUERY_DEVICE_ROUTINE)
queryDevice->CallbackRoutine)(
queryDevice->MiniportHwDeviceExtension,
queryDevice->MiniportContext,
queryDevice->DeviceDataType,
GetIoQueryDeviceInfo(deviceInformation,
IoQueryDeviceIdentifier),
GetIoQueryDeviceInfoLength(deviceInformation,
IoQueryDeviceIdentifier),
GetIoQueryDeviceInfo(deviceInformation,
IoQueryDeviceConfigurationData),
GetIoQueryDeviceInfoLength(deviceInformation,
IoQueryDeviceConfigurationData),
GetIoQueryDeviceInfo(deviceInformation,
IoQueryDeviceComponentInformation),
GetIoQueryDeviceInfoLength(deviceInformation,
IoQueryDeviceComponentInformation)
)) {
return STATUS_SUCCESS;
} else {
return STATUS_DEVICE_DOES_NOT_EXIST;
}
break;
default:
ASSERT(FALSE);
return STATUS_UNSUCCESSFUL;
}
} // end pVideoPortGetDeviceDataRegistry()
VP_STATUS
VideoPortGetDeviceData(
PVOID HwDeviceExtension,
VIDEO_DEVICE_DATA_TYPE DeviceDataType,
PMINIPORT_QUERY_DEVICE_ROUTINE CallbackRoutine,
PVOID Context
)
/*++
Routine Description:
VideoPortGetDeviceData retrieves information from the hardware hive in
the registry. The information retrieved from the registry is
bus-specific or hardware-specific.
Arguments:
HwDeviceExtension - Points to the miniport driver's device extension.
DeviceDataType - Specifies the type of data being requested (as indicated
in VIDEO_DEVICE_DATA_TYPE).
CallbackRoutine - Points to a function that should be called back with
the requested information.
Context - Specifies a context parameter passed to the callback function.
Return Value:
This function returns the final status of the operation.
Environment:
This routine cannot be called from a miniport routine synchronized with
VideoPortSynchronizeRoutine or from an ISR.
--*/
{
#define CMOS_MAX_DATA_SIZE 66000
NTSTATUS ntStatus;
VP_STATUS vpStatus;
PDEVICE_EXTENSION deviceExtension =
deviceExtension = ((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
VP_QUERY_DEVICE queryDevice;
PUCHAR cmosData = NULL;
ULONG cmosDataSize;
ULONG exCmosDataSize;
UNICODE_STRING Identifier;
PULONG pConfiguration = NULL;
PULONG pComponent = NULL;
queryDevice.MiniportHwDeviceExtension = HwDeviceExtension;
queryDevice.DeviceDataType = DeviceDataType;
queryDevice.CallbackRoutine = CallbackRoutine;
queryDevice.MiniportStatus = NO_ERROR;
queryDevice.MiniportContext = Context;
switch (DeviceDataType) {
case VpMachineData:
pVideoDebugPrint((2, "VPGetDeviceData MachineData\n"));
ntStatus = STATUS_UNSUCCESSFUL;
pConfiguration = ExAllocatePool(PagedPool, 0x1000);
pComponent = ExAllocatePool(PagedPool, 0x1000);
if (pConfiguration && pComponent)
{
RTL_QUERY_REGISTRY_TABLE QueryTable[] = {
{ NULL,
RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED,
L"Identifier",
&Identifier,
REG_NONE,
NULL,
0
},
{ NULL,
RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED,
L"Configuration Data",
pConfiguration,
REG_NONE,
NULL,
0
},
{ NULL,
RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED,
L"Component Information",
pComponent,
REG_NONE,
NULL,
0
},
// Null entry to mark the end
{ 0, 0, 0, 0, 0, 0, 0 }
};
//
// The first DWORD of the buffer contains the size of the buffer.
// Upon return, the first return contains the size of the data in the buffer.
//
// A NULL bufferint he UNICODE_STRING means the unicode string will be set up automatically
//
*pConfiguration = 0x1000 - 4;
*pComponent = 0x1000 - 4;
Identifier.Buffer = NULL;
if (NT_SUCCESS(RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
L"\\Registry\\Machine\\Hardware\\Description\\System",
QueryTable,
NULL,
NULL)))
{
vpStatus = ((PMINIPORT_QUERY_DEVICE_ROUTINE) CallbackRoutine)(
HwDeviceExtension,
Context,
DeviceDataType,
Identifier.Buffer,
Identifier.Length,
pConfiguration + 1,
*pConfiguration,
pComponent + 1,
*pComponent);
if (vpStatus == NO_ERROR)
{
ntStatus = STATUS_SUCCESS;
}
}
if (Identifier.Buffer)
{
ExFreePool(Identifier.Buffer);
}
}
//
// Free up the resources
//
if (pConfiguration)
{
ExFreePool(pConfiguration);
}
if (pComponent)
{
ExFreePool(pComponent);
}
break;
case VpCmosData:
pVideoDebugPrint((2, "VPGetDeviceData CmosData - not implemented\n"));
cmosData = ExAllocatePool(PagedPool, CMOS_MAX_DATA_SIZE);
//
// Allocate enough pool to store all the CMOS data.
//
if (!cmosData) {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
break;
}
cmosDataSize = HalGetBusData(Cmos,
0, // bus 0 returns standard Cmos info
0, // no slot number
cmosData,
CMOS_MAX_DATA_SIZE);
exCmosDataSize = HalGetBusData(Cmos,
1, // bus 1 returns extended Cmos info
0, // no slot number
cmosData + cmosDataSize,
CMOS_MAX_DATA_SIZE - cmosDataSize);
//
// Call the miniport driver callback routine
//
if (NO_ERROR == CallbackRoutine(HwDeviceExtension,
Context,
DeviceDataType,
NULL,
0,
cmosData,
cmosDataSize + exCmosDataSize,
NULL,
0)) {
ntStatus = STATUS_SUCCESS;
} else {
ntStatus = STATUS_DEVICE_DOES_NOT_EXIST;
}
break;
break;
case VpBusData:
pVideoDebugPrint((2, "VPGetDeviceData BusData\n"));
ntStatus = IoQueryDeviceDescription(&deviceExtension->AdapterInterfaceType,
&deviceExtension->SystemIoBusNumber,
NULL,
NULL,
NULL,
NULL,
&pVideoPortGetDeviceDataRegistry,
(PVOID)(&queryDevice));
break;
case VpControllerData:
pVideoDebugPrint((2, "VPGetDeviceData ControllerData\n"));
//
// Increment the controller number since we want to get info on the
// new controller.
// We do a pre-increment since the number must remain the same for
// monitor queries.
//
VpQueryDeviceControllerNumber++;
ntStatus = IoQueryDeviceDescription(&deviceExtension->AdapterInterfaceType,
&deviceExtension->SystemIoBusNumber,
&VpQueryDeviceControllerType,
&VpQueryDeviceControllerNumber,
NULL,
NULL,
&pVideoPortGetDeviceDataRegistry,
(PVOID)(&queryDevice));
//
// Reset the Peripheral number to zero since we are working on a new
// Controller.
//
VpQueryDevicePeripheralNumber = 0;
break;
case VpMonitorData:
pVideoDebugPrint((2, "VPGetDeviceData MonitorData\n"));
//
// BUGBUG Get the monitor info from the user registry first.
//
ntStatus = IoQueryDeviceDescription(&deviceExtension->AdapterInterfaceType,
&deviceExtension->SystemIoBusNumber,
&VpQueryDeviceControllerType,
&VpQueryDeviceControllerNumber,
&VpQueryDevicePeripheralType,
&VpQueryDevicePeripheralNumber,
&pVideoPortGetDeviceDataRegistry,
(PVOID)(&queryDevice));
//
// Increment the peripheral number since we have the info on this
// monitor already.
//
VpQueryDevicePeripheralNumber++;
break;
default:
pVideoDebugPrint((1, "VPGetDeviceData invalid Data type\n"));
ASSERT(FALSE);
ntStatus = STATUS_UNSUCCESSFUL;
}
//
// Free the pool we may have allocated
//
if (cmosData) {
ExFreePool(cmosData);
}
if (NT_SUCCESS(ntStatus)) {
return NO_ERROR;
} else {
pVideoDebugPrint((1, "VPGetDeviceData failed: return status is %08lx\n", ntStatus));
return ERROR_INVALID_PARAMETER;
}
} // end VideoPortGetDeviceData()
NTSTATUS
pVideoPortGetRegistryCallback(
IN PWSTR ValueName,
IN ULONG ValueType,
IN PVOID ValueData,
IN ULONG ValueLength,
IN PVOID Context,
IN PVOID EntryContext
)
/*++
Routine Description:
This routine gets information from the system hive, user-specified
registry (as opposed to the information gathered by ntdetect.
Arguments:
ValueName - Pointer to a unicode String containing the name of the data
value being searched for.
ValueType - Type of the data value.
ValueData - Pointer to a buffer containing the information to be written
out to the registry.
ValueLength - Size of the data being written to the registry.
Context - Specifies a context parameter passed to the callback routine.
EntryContext - Specifies a second context parameter passed with the
request.
Return Value:
STATUS_SUCCESS
Environment:
This routine cannot be called from a miniport routine synchronized with
VideoPortSynchronizeRoutine or from an ISR.
--*/
{
PVP_QUERY_DEVICE queryDevice = Context;
UNICODE_STRING unicodeString;
OBJECT_ATTRIBUTES objectAttributes;
NTSTATUS ntStatus = STATUS_SUCCESS;
HANDLE fileHandle = NULL;
IO_STATUS_BLOCK ioStatusBlock;
FILE_STANDARD_INFORMATION fileStandardInfo;
PVOID fileBuffer = NULL;
LARGE_INTEGER byteOffset;
//
// If the parameter was a file to be opened, perform the operation
// here. Otherwise just return the data.
//
if (queryDevice->DeviceDataType == VP_GET_REGISTRY_FILE) {
//
// For the name of the file to be valid, we must first append
// \DosDevices in front of it.
//
RtlInitUnicodeString(&unicodeString,
ValueData);
InitializeObjectAttributes(&objectAttributes,
&unicodeString,
OBJ_CASE_INSENSITIVE,
(HANDLE) NULL,
(PSECURITY_DESCRIPTOR) NULL);
ntStatus = ZwOpenFile(&fileHandle,
FILE_GENERIC_READ | SYNCHRONIZE,
&objectAttributes,
&ioStatusBlock,
0,
FILE_SYNCHRONOUS_IO_ALERT);
if (!NT_SUCCESS(ntStatus)) {
pVideoDebugPrint((1, "VideoPortGetRegistryParameters: Could not open file\n"));
goto EndRegistryCallback;
}
ntStatus = ZwQueryInformationFile(fileHandle,
&ioStatusBlock,
&fileStandardInfo,
sizeof(FILE_STANDARD_INFORMATION),
FileStandardInformation);
if (!NT_SUCCESS(ntStatus)) {
pVideoDebugPrint((1, "VideoPortGetRegistryParameters: Could not get size of file\n"));
goto EndRegistryCallback;
}
if (fileStandardInfo.EndOfFile.HighPart) {
//
// If file is too big, do not try to go further.
//
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto EndRegistryCallback;
}
ValueLength = fileStandardInfo.EndOfFile.LowPart;
fileBuffer = ExAllocatePool(PagedPool, ValueLength);
if (!fileBuffer) {
pVideoDebugPrint((1, "VideoPortGetRegistryParameters: Could not allocate buffer to read file\n"));
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto EndRegistryCallback;
}
ValueData = fileBuffer;
//
// Read the entire file for the beginning.
//
byteOffset.LowPart = byteOffset.HighPart = 0;
ntStatus = ZwReadFile(fileHandle,
NULL,
NULL,
NULL,
&ioStatusBlock,
ValueData,
ValueLength,
&byteOffset,
NULL);
if (!NT_SUCCESS(ntStatus)) {
pVideoDebugPrint((1, "VidoePortGetRegistryParameters: Could not read file\n"));
goto EndRegistryCallback;
}
}
//
// Call the miniport with the appropriate information.
//
queryDevice->MiniportStatus = ((PMINIPORT_GET_REGISTRY_ROUTINE)
queryDevice->CallbackRoutine) (queryDevice->MiniportHwDeviceExtension,
queryDevice->MiniportContext,
ValueName,
ValueData,
ValueLength);
EndRegistryCallback:
if (fileHandle) {
ZwClose(fileHandle);
}
if (fileBuffer) {
ExFreePool(fileBuffer);
}
return ntStatus;
} // end pVideoPortGetRegistryCallback()
VP_STATUS
VideoPortGetRegistryParameters(
PVOID HwDeviceExtension,
PWSTR ParameterName,
UCHAR IsParameterFileName,
PMINIPORT_GET_REGISTRY_ROUTINE CallbackRoutine,
PVOID Context
)
/*++
Routine Description:
VideoPortGetRegistryParameters retrieves information from the
CurrentControlSet in the registry. The function automatically searches
for the specified parameter name under the \Devicexxx key for the
current driver.
Arguments:
HwDeviceExtension - Points to the miniport driver's device extension.
ParameterName - Points to a Unicode string that contains the name of the
data value being searched for in the registry.
IsParameterFileName - If 1, the data retrieved from the requested
parameter name is treated as a file name. The contents of the file are
returned, instead of the parameter itself.
CallbackRoutine - Points to a function that should be called back with
the requested information.
Context - Specifies a context parameter passed to the callback routine.
Return Value:
This function returns the final status of the operation.
Environment:
This routine cannot be called from a miniport routine synchronized with
VideoPortSynchronizeRoutine or from an ISR.
--*/
{
PDEVICE_EXTENSION deviceExtension =
((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
RTL_QUERY_REGISTRY_TABLE queryTable[2];
NTSTATUS ntStatus;
VP_QUERY_DEVICE queryDevice;
queryDevice.MiniportHwDeviceExtension = HwDeviceExtension;
queryDevice.DeviceDataType = IsParameterFileName ? VP_GET_REGISTRY_FILE : VP_GET_REGISTRY_DATA;
queryDevice.CallbackRoutine = CallbackRoutine;
queryDevice.MiniportStatus = NO_ERROR;
queryDevice.MiniportContext = Context;
//
// BUGBUG
// Can be simplified now since we don't have to go down a directory.
// It can be just one call.
//
queryTable[0].QueryRoutine = pVideoPortGetRegistryCallback;
queryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
queryTable[0].Name = ParameterName;
queryTable[0].EntryContext = NULL;
queryTable[0].DefaultType = REG_NONE;
queryTable[0].DefaultData = 0;
queryTable[0].DefaultLength = 0;
queryTable[1].QueryRoutine = NULL;
queryTable[1].Flags = 0;
queryTable[1].Name = NULL;
queryTable[1].EntryContext = NULL;
queryTable[1].DefaultType = REG_NONE;
queryTable[1].DefaultData = 0;
queryTable[1].DefaultLength = 0;
ntStatus = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
deviceExtension->DriverRegistryPath,
queryTable,
&queryDevice,
NULL);
if (!NT_SUCCESS(ntStatus)) {
queryDevice.MiniportStatus = ERROR_INVALID_PARAMETER;
}
return queryDevice.MiniportStatus;
} // end VideoPortGetRegistryParameters()
VOID
pVPInit(
VOID
)
/*++
Routine Description:
First time initialization of the video port.
Normally, this is the stuff we should put in the DriverEntry routine.
However, the video port is being loaded as a DLL, and the DriverEntry
is never called. It would just be too much work to add it back to the hive
and setup.
This little routine works just as well.
--*/
{
UNICODE_STRING UnicodeString;
OBJECT_ATTRIBUTES ObjectAttributes;
NTSTATUS Status;
HANDLE hkRegistry;
UCHAR OptionsData[512];
//
// DetectDisplay == Basevideo is only TRUE on ALPHA and X86 since
// the vga driver can not always run on MIPS or PPC (due to lack of
// BIOS on some machines).
//
#if defined(_X86_) || defined(_ALPHA_)
//
// Check for a new driver installation
//
RtlInitUnicodeString(&UnicodeString,
L"\\Registry\\Machine\\System\\CurrentControlSet"
L"\\Control\\GraphicsDrivers\\DetectDisplay");
InitializeObjectAttributes(&ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = ZwOpenKey(&hkRegistry,
GENERIC_READ | GENERIC_WRITE,
&ObjectAttributes);
if (NT_SUCCESS(Status)) {
VpBaseVideo = TRUE;
ZwClose(hkRegistry);
}
#endif
//
// Check for basevideo from the start options
//
RtlInitUnicodeString(&UnicodeString,
L"\\Registry\\Machine\\System\\CurrentControlSet"
L"\\Control");
InitializeObjectAttributes(&ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = ZwOpenKey(&hkRegistry,
GENERIC_READ | GENERIC_WRITE,
&ObjectAttributes);
if (NT_SUCCESS(Status)) {
PVOID pwszOptions;
ULONG returnSize;
RtlInitUnicodeString(&UnicodeString,
L"SystemStartOptions");
Status = ZwQueryValueKey(hkRegistry,
&UnicodeString,
KeyValueFullInformation,
OptionsData,
sizeof(OptionsData),
&returnSize);
if ((NT_SUCCESS(Status)) &&
(((PKEY_VALUE_FULL_INFORMATION)OptionsData)->DataLength) &&
(((PKEY_VALUE_FULL_INFORMATION)OptionsData)->DataOffset)) {
pwszOptions = ((PUCHAR)OptionsData) +
((PKEY_VALUE_FULL_INFORMATION)OptionsData)->DataOffset;
if (wcsstr(pwszOptions, L"BASEVIDEO")) {
VpBaseVideo = TRUE;
}
}
ZwClose(hkRegistry);
}
if (VpBaseVideo == TRUE) {
//
// If we are in Basevideo mode, then create a key and value in the
// currentcontrolset part of the hardware profile that USER will
// read to determine if the vga driver should be used or not.
//
RtlInitUnicodeString(&UnicodeString,
L"\\Registry\\Machine\\System\\CurrentControlSet\\"
L"Control\\GraphicsDrivers\\BaseVideo");
InitializeObjectAttributes(&ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = ZwCreateKey(&hkRegistry,
GENERIC_READ | GENERIC_WRITE,
&ObjectAttributes,
0L,
NULL,
REG_OPTION_VOLATILE,
NULL);
if (NT_SUCCESS(Status)) {
ZwClose(hkRegistry);
} else {
ASSERT(FALSE);
}
}
}
NTSTATUS
pVideoPortInitializeBusCallback(
IN PVOID Context,
IN PUNICODE_STRING PathName,
IN INTERFACE_TYPE BusType,
IN ULONG BusNumber,
IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
IN CONFIGURATION_TYPE ControllerType,
IN ULONG ControllerNumber,
IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
IN CONFIGURATION_TYPE PeripheralType,
IN ULONG PeripheralNumber,
IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
)
{
return STATUS_SUCCESS;
} // end pVideoPortInitializeBusCallback()
VP_STATUS
pVideoPorInitializeDebugCallback(
PVOID HwDeviceExtension,
PVOID Context,
PWSTR ValueName,
PVOID ValueData,
ULONG ValueLength
)
{
pVideoDebugPrint((2, "VIDEOPRT: Getting debug level from miniport driver\n"));
if (ValueLength && ValueData) {
VideoDebugLevel = *((PULONG)ValueData);
return NO_ERROR;
} else {
return ERROR_INVALID_PARAMETER;
}
} // end pVideoPorInitializeDebugCallback()
ULONG
pVideoPortMaxLockedMemory(
VOID
)
{
ULONG maxlockedmemory = 0x80000;
switch(MmQuerySystemSize()){
case MmMediumSystem:
maxlockedmemory = 0x200000;
break;
case MmLargeSystem:
maxlockedmemory = 0x400000;
break;
default:
break;
}
return maxlockedmemory;
}
#define MAX_LOCKED_MEMORY pVideoPortMaxLockedMemory()
ULONG
VideoPortInitialize(
IN PVOID Argument1,
IN PVOID Argument2,
IN PVIDEO_HW_INITIALIZATION_DATA HwInitializationData,
IN PVOID HwContext
)
/*++
Routine Description:
VideoPortInitialize is called from the initial entry point of a miniport
driver. It performs the initialization of the driver.
Arguments:
Argument1 - Specifies the first parameter with which the operating
system called the miniport driver initialization function.
Argument2 - Specifies the second parameter with which the operating
system called the miniport driver initialization function.
HwInitializationData - Points to the miniport driver structure
VIDEO_HW_INITIALIZATION_DATA.
HwContext - Specifies a context parameter that is passed to the
HwFindAdapter (*PVIDEO_HW_FIND_ADAPTER) function of the miniport
driver.
Return Value:
This function returns the final status of the initialization operation.
If it is called several times, the calling function should return the
smallest of the codes returned from VideoPortInitialize.
Environment:
This routine cannot be called from a miniport routine synchronized with
VideoPortSynchronizeRoutine or from an ISR.
--*/
{
#define STRING_LENGTH 60
PDRIVER_OBJECT driverObject = Argument1;
ULONG busNumber = 0;
ULONG extensionAllocationSize;
WCHAR deviceNameBuffer[STRING_LENGTH];
WCHAR ntNumberBuffer[STRING_LENGTH];
UNICODE_STRING deviceNameUnicodeString;
UNICODE_STRING ntNumberUnicodeString;
NTSTATUS ntStatus;
BOOLEAN statusNoError = FALSE;
WCHAR deviceSubpathBuffer[STRING_LENGTH];
UNICODE_STRING deviceSubpathUnicodeString;
WCHAR deviceLinkBuffer[STRING_LENGTH];
UNICODE_STRING deviceLinkUnicodeString;
UCHAR nextMiniport;
KAFFINITY affinity;
if (VPFirstTime)
{
VPFirstTime = FALSE;
pVPInit();
}
//
// Check if the size of the pointer, or the size of the data passed in
// are OK.
//
ASSERT(HwInitializationData != NULL);
if (HwInitializationData->HwInitDataSize >
sizeof(VIDEO_HW_INITIALIZATION_DATA) ) {
pVideoDebugPrint((0, "VideoPortInitialize: Invalid initialization data size\n"));
return ((ULONG) STATUS_REVISION_MISMATCH);
}
//
// Check that each required entry is not NULL.
//
if ((!HwInitializationData->HwFindAdapter) ||
(!HwInitializationData->HwInitialize) ||
(!HwInitializationData->HwStartIO)) {
pVideoDebugPrint((1, "VideoPortInitialize: miniport missing required entry\n"));
return ((ULONG)STATUS_REVISION_MISMATCH);
}
//
// Reset the controller number used in IoQueryDeviceDescription to zero
// since we are restarting on a new type of bus.
// Note: PeripheralNumber is reset only when we find a new controller.
//
VpQueryDeviceControllerNumber = 0xFFFFFFFF;
//
// Determine size of the device extension to allocate.
//
extensionAllocationSize = sizeof(DEVICE_EXTENSION) +
HwInitializationData->HwDeviceExtensionSize;
//
// Check if we are on the right Bus Adapter type.
// If we are not, then return immediately.
//
ASSERT (HwInitializationData->AdapterInterfaceType < MaximumInterfaceType);
//
// Assume we are going to fail this the IoQueryDeviceDescription call
// and that no device is found.
//
ntStatus = STATUS_NO_SUCH_DEVICE;
while (NT_SUCCESS(IoQueryDeviceDescription(
&HwInitializationData->AdapterInterfaceType,
&busNumber,
NULL,
NULL,
NULL,
NULL,
&pVideoPortInitializeBusCallback,
NULL))) {
//
// This is to support the multiple initialization as described by the
// again paramter in HwFindAdapter.
// We must repeat almost everything in this function until FALSE is
// returned by the miniport. This is why we test for the condition at
// the end. Freeing of data structure has to be done also since we want
// to delete a device object for a device that did not load properly.
//
do {
PVIDEO_PORT_CONFIG_INFO miniportConfigInfo = NULL;
PDEVICE_OBJECT deviceObject = NULL;
PDEVICE_EXTENSION deviceExtension;
VP_STATUS findAdapterStatus = ERROR_DEV_NOT_EXIST;
ULONG driverKeySize;
PWSTR driverKeyName = NULL;
BOOLEAN symbolicLinkCreated = FALSE;
UNICODE_STRING physicalMemoryUnicodeString;
OBJECT_ATTRIBUTES objectAttributes;
HANDLE physicalMemoryHandle = NULL;
nextMiniport = FALSE;
//
// Allocate the buffer in which the miniport driver will store all the
// configuration information.
//
miniportConfigInfo = (PVIDEO_PORT_CONFIG_INFO)
ExAllocatePool(PagedPool,
sizeof(VIDEO_PORT_CONFIG_INFO));
if (miniportConfigInfo == NULL) {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto EndOfInitialization;
}
RtlZeroMemory((PVOID) miniportConfigInfo,
sizeof(VIDEO_PORT_CONFIG_INFO));
miniportConfigInfo->Length = sizeof(VIDEO_PORT_CONFIG_INFO);
//
// Put in the BusType specified within the HW_INITIALIZATION_DATA
// structure by the miniport and the bus number inthe miniport config info.
//
miniportConfigInfo->SystemIoBusNumber = busNumber;
miniportConfigInfo->AdapterInterfaceType =
HwInitializationData->AdapterInterfaceType;
//
// Initialize the type of interrupt based on the bus type.
//
switch (miniportConfigInfo->AdapterInterfaceType) {
case Internal:
case MicroChannel:
case PCIBus:
miniportConfigInfo->InterruptMode = LevelSensitive;
break;
default:
miniportConfigInfo->InterruptMode = Latched;
break;
}
//
// Save away the some of the attributes.
//
miniportConfigInfo->MaximumTransferLength = 0;
miniportConfigInfo->NumberOfPhysicalBreaks = 0;
miniportConfigInfo->DmaChannel = 0;
miniportConfigInfo->DmaPort = 0;
miniportConfigInfo->NeedPhysicalAddresses = HwInitializationData->NeedPhysicalAddresses;
miniportConfigInfo->bMapBuffers = HwInitializationData->bMapBuffers;
//
// BUGBUG
// What do we do about the Bus type for the device since the query device
// infromation can scan multiple buses?
// Do we want to callback for each new bus type?
//
//
// Set up the device driver entry points.
//
driverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = pVideoPortDispatch;
driverObject->MajorFunction[IRP_MJ_CREATE] = pVideoPortDispatch;
driverObject->MajorFunction[IRP_MJ_CLOSE] = pVideoPortDispatch;
//
// NOTE Port driver should eventually handle unload.
//
//
// Create the miniport driver object name.
//
ntNumberUnicodeString.Buffer = ntNumberBuffer;
ntNumberUnicodeString.Length = 0;
ntNumberUnicodeString.MaximumLength = STRING_LENGTH;
if (!NT_SUCCESS(RtlIntegerToUnicodeString(
VideoDeviceNumber,
10,
&ntNumberUnicodeString))) {
pVideoDebugPrint((1, "VideoPortInitialize: Could not create device number\n"));
goto EndOfInitialization;
}
deviceNameUnicodeString.Buffer = deviceNameBuffer;
deviceNameUnicodeString.Length = 0;
deviceNameUnicodeString.MaximumLength = STRING_LENGTH;
if (!NT_SUCCESS(RtlAppendUnicodeToString(&deviceNameUnicodeString,
L"\\Device\\Video"))) {
pVideoDebugPrint((1, "VideoPortInitialize: Could not create base device name\n"));
goto EndOfInitialization;
}
if (!NT_SUCCESS(RtlAppendUnicodeStringToString(&deviceNameUnicodeString,
&ntNumberUnicodeString))) {
pVideoDebugPrint((1, "VideoPortInitialize: Could not append device number\n"));
goto EndOfInitialization;
}
//
// Create a device object to represent the Video Adapter.
//
deviceNameUnicodeString.MaximumLength = (USHORT)
(deviceNameUnicodeString.Length + sizeof( UNICODE_NULL ));
ntStatus = IoCreateDevice(driverObject,
extensionAllocationSize,
&deviceNameUnicodeString,
FILE_DEVICE_VIDEO,
0,
TRUE,
&deviceObject);
//
// We keep the unicode string around because we will want to use it to
// store the device name in the registry.
//
if (!NT_SUCCESS(ntStatus)) {
pVideoDebugPrint((1, "VideoPortInitialize: Could not create device object\n"));
goto EndOfInitialization;
}
//
// Mark this object as supporting buffered I/O so that the I/O system
// will only supply simple buffers in IRPs.
//
deviceObject->Flags |= DO_BUFFERED_IO;
//
// Set up device extension pointers and sizes
//
deviceExtension = deviceObject->DeviceExtension;
deviceExtension->DeviceObject = deviceObject;
deviceExtension->HwDeviceExtension = (PVOID)(deviceExtension + 1);
deviceExtension->HwDeviceExtensionSize =
HwInitializationData->HwDeviceExtensionSize;
deviceExtension->MiniportConfigInfo = miniportConfigInfo;
//
// Save the dependent driver routines in the device extension.
//
deviceExtension->HwFindAdapter = HwInitializationData->HwFindAdapter;
deviceExtension->HwInitialize = HwInitializationData->HwInitialize;
deviceExtension->HwInterrupt = HwInitializationData->HwInterrupt;
deviceExtension->HwStartIO = HwInitializationData->HwStartIO;
//
// Put in the information about the bus in the deviceExtension.
//
deviceExtension->SystemIoBusNumber = busNumber;
deviceExtension->AdapterInterfaceType =
HwInitializationData->AdapterInterfaceType;
//
// Create the name we will be storing in the \DeviceMap.
// This name is a PWSTR, not a unicode string
// This is the name of the driver with an appended device number
//
ntNumberUnicodeString.Buffer = ntNumberBuffer;
ntNumberUnicodeString.Length = 0;
ntNumberUnicodeString.MaximumLength = STRING_LENGTH;
if (!NT_SUCCESS(RtlIntegerToUnicodeString(
HwInitializationData->StartingDeviceNumber,
10,
&ntNumberUnicodeString))) {
pVideoDebugPrint((1, "VideoPortInitialize: Could not create device subpath number\n"));
goto EndOfInitialization;
}
deviceSubpathUnicodeString.Buffer = deviceSubpathBuffer;
deviceSubpathUnicodeString.Length = 0;
deviceSubpathUnicodeString.MaximumLength = STRING_LENGTH;
if (!NT_SUCCESS(RtlAppendUnicodeToString(&deviceSubpathUnicodeString,
L"\\Device"))) {
pVideoDebugPrint((1, "VideoPortInitialize: Could not create base device subpath name\n"));
goto EndOfInitialization;
}
if (!NT_SUCCESS(RtlAppendUnicodeStringToString(&deviceSubpathUnicodeString,
&ntNumberUnicodeString))) {
pVideoDebugPrint((1, "VideoPortInitialize: Could not append device subpath number\n"));
goto EndOfInitialization;
}
driverKeySize = ((PUNICODE_STRING)Argument2)->Length +
deviceSubpathUnicodeString.Length + sizeof(UNICODE_NULL);
if ( (driverKeyName = (PWSTR) ExAllocatePool(PagedPool,
driverKeySize) ) == NULL) {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto EndOfInitialization;
}
RtlMoveMemory(driverKeyName,
((PUNICODE_STRING)Argument2)->Buffer,
((PUNICODE_STRING)Argument2)->Length);
RtlMoveMemory((PWSTR)( (ULONG)driverKeyName +
((PUNICODE_STRING)Argument2)->Length ),
deviceSubpathBuffer,
deviceSubpathUnicodeString.Length);
*((PWSTR) ((ULONG)driverKeyName +
(driverKeySize - sizeof(UNICODE_NULL)))) = UNICODE_NULL;
//
// Store the path name of the location of the driver in the registry.
//
deviceExtension->DriverRegistryPath = driverKeyName;
//
// Initialize the dispatch event object. Allows us to synchronize
// requests being sent to the miniport driver.
//
KeInitializeEvent(&deviceExtension->SyncEvent,
SynchronizationEvent,
TRUE);
//
// Initialize the DPC object used for error logging.
//
KeInitializeDpc(&deviceExtension->ErrorLogDpc,
pVideoPortLogErrorEntryDPC,
deviceObject);
//
// Turn on the debug level based on the miniport driver entry
//
VideoPortGetRegistryParameters(deviceExtension->HwDeviceExtension,
L"VideoDebugLevel",
FALSE,
pVideoPorInitializeDebugCallback,
NULL);
//
// Call the miniport find adapter routine to determine if an adapter is
// actually present in the system.
//
findAdapterStatus =
deviceExtension->HwFindAdapter(deviceExtension->HwDeviceExtension,
HwContext,
NULL, // BUGBUG What is this string?
miniportConfigInfo,
&nextMiniport);
//
// If the adapter is not found, display an error.
//
if (findAdapterStatus != NO_ERROR) {
pVideoDebugPrint((1, "VideoPortInitialize: Find adapter failed\n"));
ntStatus = STATUS_UNSUCCESSFUL;
goto EndOfInitialization;
}
//
// Store the emulator data in the device extension so we can use it
// later.
//
deviceExtension->NumEmulatorAccessEntries =
miniportConfigInfo->NumEmulatorAccessEntries;
deviceExtension->EmulatorAccessEntries =
miniportConfigInfo->EmulatorAccessEntries;
deviceExtension->EmulatorAccessEntriesContext =
miniportConfigInfo->EmulatorAccessEntriesContext;
deviceExtension->ServerBiosAddressSpaceInitialized = FALSE;
deviceExtension->VdmPhysicalVideoMemoryAddress =
miniportConfigInfo->VdmPhysicalVideoMemoryAddress;
deviceExtension->VdmPhysicalVideoMemoryLength =
miniportConfigInfo->VdmPhysicalVideoMemoryLength;
//
// Store the required information in the device extension for later use.
//
deviceExtension->HardwareStateSize =
miniportConfigInfo->HardwareStateSize;
//
// If the device supplies an interrupt service routine, we must
// set up all the structures to support interrupts. Otherwise,
// they can be ignored.
//
if (deviceExtension->HwInterrupt &&
((miniportConfigInfo->BusInterruptLevel != 0) ||
(miniportConfigInfo->BusInterruptVector != 0)) ) {
//
// Note: the spinlock for the interrupt object is created
// internally by the IoConnectInterrupt() call. It is also
// used internally by KeSynchronizeExecution.
//
deviceExtension->InterruptVector =
HalGetInterruptVector(deviceExtension->AdapterInterfaceType,
deviceExtension->SystemIoBusNumber,
miniportConfigInfo->BusInterruptLevel,
miniportConfigInfo->BusInterruptVector,
&deviceExtension->InterruptIrql,
&affinity);
deviceExtension->InterruptMode = miniportConfigInfo->InterruptMode;
ntStatus = IoConnectInterrupt(&deviceExtension->InterruptObject,
(PKSERVICE_ROUTINE) pVideoPortInterrupt,
deviceObject,
NULL,
deviceExtension->InterruptVector,
deviceExtension->InterruptIrql,
deviceExtension->InterruptIrql,
deviceExtension->InterruptMode,
(BOOLEAN) ((miniportConfigInfo->InterruptMode ==
LevelSensitive) ? TRUE : FALSE),
affinity,
FALSE);
if (!NT_SUCCESS(ntStatus)) {
pVideoDebugPrint((1, "VideoPortInitialize: Can't connect interrupt\n"));
goto EndOfInitialization;
}
} else {
deviceExtension->HwInterrupt = NULL;
}
//
// DMA support
//
deviceExtension->HwStartDma = HwInitializationData->HwStartDma;
//
// Determine if a Dma Adapter must be allocated.
//
if (deviceExtension->DmaAdapterObject == NULL &&
(miniportConfigInfo->Master ||
miniportConfigInfo->DmaChannel != 0)) {
DEVICE_DESCRIPTION deviceDescription;
ULONG numberOfMapRegisters;
//
// Get the adapter object for this card.
//
RtlZeroMemory(&deviceDescription, sizeof(deviceDescription));
deviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
deviceDescription.DmaChannel = miniportConfigInfo->DmaChannel;
deviceDescription.BusNumber = miniportConfigInfo->SystemIoBusNumber;
deviceDescription.DmaWidth = miniportConfigInfo->DmaWidth;
deviceDescription.DmaSpeed = miniportConfigInfo->DmaSpeed;
deviceDescription.ScatterGather = miniportConfigInfo->ScatterGather;
deviceDescription.Master = miniportConfigInfo->Master;
deviceDescription.DmaPort = miniportConfigInfo->DmaPort;
deviceDescription.Dma32BitAddresses = miniportConfigInfo->Dma32BitAddresses;
deviceDescription.AutoInitialize = FALSE;
deviceDescription.DemandMode = miniportConfigInfo->DemandMode;
deviceDescription.MaximumLength = miniportConfigInfo->MaximumTransferLength;
deviceDescription.InterfaceType = deviceExtension->AdapterInterfaceType;
deviceExtension->DmaAdapterObject = HalGetAdapter(&deviceDescription,
&numberOfMapRegisters);
ASSERT(deviceExtension->DmaAdapterObject);
if (numberOfMapRegisters * PAGE_SIZE > MAX_LOCKED_MEMORY)
numberOfMapRegisters = MAX_LOCKED_MEMORY/PAGE_SIZE;
//
// Set maximum number of page breaks.
//
if (numberOfMapRegisters > miniportConfigInfo->NumberOfPhysicalBreaks) {
deviceExtension->Capabilities.MaximumPhysicalPages = miniportConfigInfo->NumberOfPhysicalBreaks;
} else {
deviceExtension->Capabilities.MaximumPhysicalPages = numberOfMapRegisters;
}
deviceExtension->FreeDmaParameters = NULL;
deviceExtension->FreeDmaParameters =
ExAllocatePool(NonPagedPool,
MAX_DMA_PARAMS * sizeof(DMA_PARAMETERS));
if (!deviceExtension->FreeDmaParameters) {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto EndOfInitialization;
}
RtlZeroMemory(deviceExtension->FreeDmaParameters,
MAX_DMA_PARAMS * sizeof(DMA_PARAMETERS));
deviceExtension->MaxQ = MAX_DMA_PARAMS;
deviceExtension->SynchronizeExecution = KeSynchronizeExecution;
}
//
// Indicate if a scatter/gather list needs to be built for DMA.
//
if (deviceExtension->DmaAdapterObject != NULL &&
miniportConfigInfo->Master &&
miniportConfigInfo->NeedPhysicalAddresses) {
deviceExtension->bMasterWithAdapter = TRUE;
} else {
deviceExtension->bMasterWithAdapter = FALSE;
} // end if (deviceExtension->DmaAdapterObject != NULL)
//
// New, Optional.
// Setup the timer if it is specified by a driver.
//
if (HwInitializationData->HwInitDataSize >
FIELD_OFFSET(VIDEO_HW_INITIALIZATION_DATA, HwTimer)) {
deviceExtension->HwTimer = HwInitializationData->HwTimer;
ntStatus = IoInitializeTimer(deviceObject,
pVideoPortHwTimer,
NULL);
//
// If we fail forget about the timer !
//
if (!NT_SUCCESS(ntStatus)) {
ASSERT(FALSE);
deviceExtension->HwTimer = NULL;
}
}
//
// New, Optional.
// Reset Hw function.
//
if (HwInitializationData->HwInitDataSize >
FIELD_OFFSET(VIDEO_HW_INITIALIZATION_DATA, HwResetHw)) {
//
// NOTE:
// Initialize the pointer here since it has never been done.
// This should be done in Driver Entry, but DriverEntry is never called ...
//
if (!HwResetHwPointer) {
HwResetHwPointer = &(HwResetHw[0]);
}
HwResetHwPointer->ResetFunction = HwInitializationData->HwResetHw;
HwResetHwPointer->HwDeviceExtension = deviceExtension->HwDeviceExtension;
HwResetHwPointer++;
}
//
// NOTE:
//
// We only want to reinitialize the device once the Boot sequence has
// been completed and the HAL does not need to access the device again.
// So the initialization entry point will be called whenthe device is
// opened.
//
//
// Get a pointer to physical memory so we can map the
// video frame buffer (and possibly video registers) into
// the caller's address space whenever he needs it.
//
// - Create the name
// - Initialize the data to find the object
// - Open a handle to the oject and check the status
// - Get a pointer to the object
// - Free the handle
//
RtlInitUnicodeString(&physicalMemoryUnicodeString,
L"\\Device\\PhysicalMemory");
InitializeObjectAttributes(&objectAttributes,
&physicalMemoryUnicodeString,
OBJ_CASE_INSENSITIVE,
(HANDLE) NULL,
(PSECURITY_DESCRIPTOR) NULL);
ntStatus = ZwOpenSection(&physicalMemoryHandle,
SECTION_ALL_ACCESS,
&objectAttributes);
if (!NT_SUCCESS(ntStatus)) {
pVideoDebugPrint((1, "VideoPortInitialize: Could not open handle to physical memory\n"));
goto EndOfInitialization;
}
ntStatus = ObReferenceObjectByHandle(physicalMemoryHandle,
SECTION_ALL_ACCESS,
(POBJECT_TYPE) NULL,
KernelMode,
&deviceExtension->PhysicalMemorySection,
(POBJECT_HANDLE_INFORMATION) NULL);
if (!NT_SUCCESS(ntStatus)) {
pVideoDebugPrint((1, "VideoPortInitialize: Could not reference physical memory\n"));
goto EndOfInitialization;
}
//
// Create symbolic link with DISPLAY so name can be used for win32 API
//
ntNumberUnicodeString.Buffer = ntNumberBuffer;
ntNumberUnicodeString.Length = 0;
ntNumberUnicodeString.MaximumLength = STRING_LENGTH;
if (!NT_SUCCESS(RtlIntegerToUnicodeString(
VideoDeviceNumber + 1,
10,
&ntNumberUnicodeString))) {
pVideoDebugPrint((1, "VideoPortInitialize: Could not create symbolic link number\n"));
goto EndOfInitialization;
}
deviceLinkUnicodeString.Buffer = deviceLinkBuffer;
deviceLinkUnicodeString.Length = 0;
deviceLinkUnicodeString.MaximumLength = STRING_LENGTH;
if (!NT_SUCCESS(RtlAppendUnicodeToString(&deviceLinkUnicodeString,
L"\\DosDevices\\DISPLAY"))) {
pVideoDebugPrint((1, "VideoPortInitialize: Could not create base device subpath name\n"));
goto EndOfInitialization;
}
if (!NT_SUCCESS(RtlAppendUnicodeStringToString(&deviceLinkUnicodeString,
&ntNumberUnicodeString))) {
pVideoDebugPrint((1, "VideoPortInitialize: Could not append device subpath number\n"));
goto EndOfInitialization;
}
ntStatus = IoCreateSymbolicLink(&deviceLinkUnicodeString,
&deviceNameUnicodeString);
if (!NT_SUCCESS(ntStatus)) {
pVideoDebugPrint((1, "VideoPortInitialize: SymbolicLink Creation failed\n"));
goto EndOfInitialization;
}
symbolicLinkCreated = TRUE;
//
// Once initialization is finished, load the required information in the
// registry so that the appropriate display drivers can be loaded.
//
ntStatus = RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP,
VideoClassString,
deviceNameBuffer,
REG_SZ,
driverKeyName,
driverKeySize);
if (!NT_SUCCESS(ntStatus)) {
pVideoDebugPrint((0, "VideoPortInitialize: Could not store name in DeviceMap\n"));
} else {
pVideoDebugPrint((1, "VideoPortInitialize: name is stored in DeviceMap\n"));
}
EndOfInitialization:
#if DBG
//
// Reset our flag for resources reported to FALSE;
//
if (VPInitPhase == FALSE) {
VPResourcesReported = FALSE;
}
#endif
if (physicalMemoryHandle) {
ZwClose(physicalMemoryHandle);
}
if (NT_SUCCESS(ntStatus)) {
//
// If nothing failed in the initialization, increase the number of
// video devices and the number of devices for this miniport.
// Then return.
//
VideoDeviceNumber++;
HwInitializationData->StartingDeviceNumber++;
//
// We use this variable to know if at least one of the tries at
// loading the device succeded. This value is initialized to FALSE
// and if at least one device is created properly, then we will
// return TRUE
//
statusNoError = TRUE;
} else {
//
// Free the miniport config info buffer.
//
if (deviceExtension->FreeDmaParameters) {
ExFreePool(deviceExtension->FreeDmaParameters);
}
if (miniportConfigInfo) {
ExFreePool(miniportConfigInfo);
}
//
// Release the resource we put in the resourcemap (if any).
//
if (findAdapterStatus != NO_ERROR) {
ULONG emptyList = 0;
BOOLEAN conflict;
IoReportResourceUsage(&VideoClassName,
driverObject,
NULL,
0L,
deviceObject,
(PCM_RESOURCE_LIST) &emptyList, // an empty resource list
sizeof(ULONG),
FALSE,
&conflict);
}
//
// These are the things we want to delete if they were created and
// the initialization *FAILED* at a later time.
//
if (deviceExtension->InterruptObject) {
IoDisconnectInterrupt(deviceExtension->InterruptObject);
}
if (driverKeyName) {
ExFreePool(driverKeyName);
}
if (symbolicLinkCreated) {
IoDeleteSymbolicLink(&deviceNameUnicodeString);
}
//
// Free up any memory mapped in by the miniport using
// VideoPort GetDeviceBase.
//
while (deviceExtension->MappedAddressList != NULL)
{
pVideoDebugPrint((0, "VideoPortInitialize: unfreed address %08lx, physical %08lx, size %08lx\n",
deviceExtension->MappedAddressList->MappedAddress,
deviceExtension->MappedAddressList->PhysicalAddress.LowPart,
deviceExtension->MappedAddressList->NumberOfUchars));
pVideoDebugPrint((0, "VideoPortInitialize: unfreed refcount %d, unmapping %d\n\n",
deviceExtension->MappedAddressList->RefCount,
deviceExtension->MappedAddressList->bNeedsUnmapping));
VideoPortFreeDeviceBase(deviceExtension->HwDeviceExtension,
deviceExtension->MappedAddressList->MappedAddress);
}
//
// Finally, delete the device object.
//
if (deviceObject) {
IoDeleteDevice(deviceObject);
}
}
} while (nextMiniport);
//
// We finished finding all the device on the current bus
// Go on to the next bus.
//
busNumber++;
}
//
// If at least one device loaded, then return success, otherwise return
// the last available error message.
//
if (statusNoError) {
return STATUS_SUCCESS;
} else {
return ((ULONG)ntStatus);
}
} // VideoPortInitialize()
BOOLEAN
pVideoPortInterrupt(
IN PKINTERRUPT Interrupt,
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
This function is the main interrupt service routine. If finds which
miniport driver the interrupt was for and forwards it.
Arguments:
Interrupt -
DeviceObject -
Return Value:
Returns TRUE if the interrupt was expected.
--*/
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
UNREFERENCED_PARAMETER(Interrupt);
//
// If there is no interrupt routine, fail the assertion
//
ASSERT (deviceExtension->HwInterrupt);
if (deviceExtension->HwInterrupt(deviceExtension->HwDeviceExtension)) {
return TRUE;
} else {
return FALSE;
}
} // pVideoPortInterrupt()
VOID
VideoPortLogError(
IN PVOID HwDeviceExtension,
IN PVIDEO_REQUEST_PACKET Vrp OPTIONAL,
IN VP_STATUS ErrorCode,
IN ULONG UniqueId
)
/*++
Routine Description:
This routine saves the error log information so it can be processed at
any IRQL.
Arguments:
HwDeviceExtension - Supplies the HBA miniport driver's adapter data storage.
Vrp - Supplies an optional pointer to a video request packet if there is
one.
ErrorCode - Supplies an error code indicating the type of error.
UniqueId - Supplies a unique identifier for the error.
Return Value:
None.
--*/
{
VP_ERROR_LOG_ENTRY errorLogEntry;
//
// Save the information in a local errorLogEntry structure.
//
errorLogEntry.DeviceExtension = ((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
if (Vrp != NULL) {
errorLogEntry.IoControlCode = Vrp->IoControlCode;
} else {
errorLogEntry.IoControlCode = 0;
}
errorLogEntry.ErrorCode = ErrorCode;
errorLogEntry.UniqueId = UniqueId;
//
// Call the sync routine so we are synchronized when writting in
// the device extension.
//
pVideoPortSynchronizeExecution(HwDeviceExtension,
VpMediumPriority,
pVideoPortLogErrorEntry,
&errorLogEntry);
return;
} // end VideoPortLogError()
BOOLEAN
pVideoPortLogErrorEntry(
IN PVOID Context
)
/*++
Routine Description:
This function is the synchronized LogError functions.
Arguments:
Context - Context value used here as the VP_ERROR_LOG_ENTRY for this
particular error
Return Value:
None.
--*/
{
PVP_ERROR_LOG_ENTRY logEntry = Context;
PDEVICE_EXTENSION deviceExtension = logEntry->DeviceExtension;
//
// If the error log entry is already full, then dump the error.
//
if (deviceExtension->InterruptFlags & VP_ERROR_LOGGED) {
pVideoDebugPrint((1, "VideoPortLogError: Dumping video error log packet.\n"));
pVideoDebugPrint((1, "ControlCode = %x, ErrorCode = %x, UniqueId = %x.\n",
logEntry->IoControlCode, logEntry->ErrorCode,
logEntry->UniqueId));
return TRUE;
}
//
// Indicate that the error log entry is in use.
//
deviceExtension->InterruptFlags |= VP_ERROR_LOGGED;
deviceExtension->ErrorLogEntry = *logEntry;
//
// Now queue a DPC so we can process the error.
//
KeInsertQueueDpc(&deviceExtension->ErrorLogDpc,
NULL,
NULL);
return TRUE;
} // end pVideoPortLogErrorEntry();
VOID
pVideoPortLogErrorEntryDPC(
IN PKDPC Dpc,
IN PVOID DeferredContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2
)
/*++
Routine Description:
This function allocates an I/O error log record, fills it in and writes it
to the I/O error log.
Arguments:
Dpc - Pointer to the DPC object.
DeferredContext - Context parameter that was passed to the DPC
initialization routine. It contains a pointer to the deviceObject.
SystemArgument1 - Unused.
SystemArgument2 - Unused.
Return Value:
None.
--*/
{
PDEVICE_OBJECT DeviceObject = DeferredContext;
PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
PIO_ERROR_LOG_PACKET errorLogPacket;
errorLogPacket = (PIO_ERROR_LOG_PACKET)
IoAllocateErrorLogEntry(DeviceObject,
sizeof(IO_ERROR_LOG_PACKET) + sizeof(ULONG));
if (errorLogPacket != NULL) {
errorLogPacket->MajorFunctionCode = IRP_MJ_DEVICE_CONTROL;
errorLogPacket->RetryCount = 0;
errorLogPacket->NumberOfStrings = 0;
errorLogPacket->StringOffset = 0;
errorLogPacket->EventCategory = 0;
//
// Translate the miniport error code into the NT I\O driver.
//
switch (DeviceExtension->ErrorLogEntry.ErrorCode) {
case ERROR_INVALID_FUNCTION:
case ERROR_INVALID_PARAMETER:
errorLogPacket->ErrorCode = IO_ERR_INVALID_REQUEST;
break;
case ERROR_NOT_ENOUGH_MEMORY:
case ERROR_INSUFFICIENT_BUFFER:
errorLogPacket->ErrorCode = IO_ERR_INSUFFICIENT_RESOURCES;
break;
case ERROR_DEV_NOT_EXIST:
errorLogPacket->ErrorCode = IO_ERR_CONFIGURATION_ERROR;
break;
case ERROR_IO_PENDING:
ASSERT(FALSE);
case ERROR_MORE_DATA:
case NO_ERROR:
errorLogPacket->ErrorCode = 0;
break;
//
// If it is another error code, than assume it is private to the
// driver and just pass as-is.
//
default:
errorLogPacket->ErrorCode =
DeviceExtension->ErrorLogEntry.ErrorCode;
break;
}
errorLogPacket->UniqueErrorValue =
DeviceExtension->ErrorLogEntry.UniqueId;
errorLogPacket->FinalStatus = STATUS_SUCCESS;
errorLogPacket->SequenceNumber = 0;
errorLogPacket->IoControlCode =
DeviceExtension->ErrorLogEntry.IoControlCode;
errorLogPacket->DumpDataSize = sizeof(ULONG);
errorLogPacket->DumpData[0] =
DeviceExtension->ErrorLogEntry.ErrorCode;
IoWriteErrorLogEntry(errorLogPacket);
}
DeviceExtension->InterruptFlags &= ~VP_ERROR_LOGGED;
} // end pVideoPortLogErrorEntry();
VOID
pVideoPortMapToNtStatus(
IN PSTATUS_BLOCK StatusBlock
)
/*++
Routine Description:
This function maps a Win32 error code to an NT error code, making sure
the inverse translation will map back to the original status code.
Arguments:
StatusBlock - Pointer to the status block
Return Value:
None.
--*/
{
PNTSTATUS status = &StatusBlock->Status;
switch (*status) {
case ERROR_INVALID_FUNCTION:
*status = STATUS_NOT_IMPLEMENTED;
break;
case ERROR_NOT_ENOUGH_MEMORY:
*status = STATUS_INSUFFICIENT_RESOURCES;
break;
case ERROR_INVALID_PARAMETER:
*status = STATUS_INVALID_PARAMETER;
break;
case ERROR_INSUFFICIENT_BUFFER:
*status = STATUS_BUFFER_TOO_SMALL;
//
// Make sure we zero out the information block if we get an
// insufficient buffer.
//
StatusBlock->Information = 0;
break;
case ERROR_MORE_DATA:
*status = STATUS_BUFFER_OVERFLOW;
break;
case ERROR_DEV_NOT_EXIST:
*status = STATUS_DEVICE_DOES_NOT_EXIST;
break;
case ERROR_IO_PENDING:
ASSERT(FALSE);
// Fall through.
case NO_ERROR:
*status = STATUS_SUCCESS;
break;
default:
//
// These must be privately defined error codes ...
// Do not redefint them
//
// BUGBUG Make sure they match the appropriate method
ASSERT(FALSE);
break;
}
return;
} // end pVideoPortMapToNtStatus()
NTSTATUS
pVideoPortMapUserPhysicalMem(
IN PDEVICE_EXTENSION DeviceExtension,
IN HANDLE ProcessHandle OPTIONAL,
IN PHYSICAL_ADDRESS PhysicalAddress,
IN OUT PULONG Length,
IN OUT PULONG InIoSpace,
IN OUT PVOID *VirtualAddress
)
/*++
Routine Description:
This function maps a view of a block of physical memory into a process'
virtual address space.
Arguments:
HwDeviceExtension - Pointer to the miniport driver's device extension.
ProcessHandle - Optional handle to the process into which the memory must
be mapped.
PhysicalAddress - Offset from the beginning of physical memory, in bytes.
Length - Pointer to a variable that will receive that actual size in
bytes of the view. The length is rounded to a page boundary. THe
length may not be zero.
InIoSpace - Specifies if the address is in the IO space if TRUE; otherwise,
the address is assumed to be in memory space.
VirtualAddress - Pointer to a variable that will receive the base
address of the view. If the initial value is not NULL, then the view
will be allocated starting at teh specified virtual address rounded
down to the next 64kb addess boundary.
Return Value:
STATUS_UNSUCCESSFUL if the length was zero.
STATUS_SUCCESS otherwise.
Environment:
This routine cannot be called from a miniport routine synchronized with
VideoPortSynchronizeRoutine or from an ISR.
--*/
{
NTSTATUS ntStatus;
HANDLE physicalMemoryHandle;
PHYSICAL_ADDRESS physicalAddressBase;
PHYSICAL_ADDRESS physicalAddressEnd;
PHYSICAL_ADDRESS viewBase;
PHYSICAL_ADDRESS mappedLength;
HANDLE processHandle;
BOOLEAN translateBaseAddress;
BOOLEAN translateEndAddress;
ULONG inIoSpace2;
ULONG inIoSpace1;
//
// Check for a length of zero. If it is, the entire physical memory
// would be mapped into the process' address space. An error is returned
// in this case.
//
if (!*Length) {
return STATUS_INVALID_PARAMETER_4;
}
if (!(*InIoSpace & VIDEO_MEMORY_SPACE_USER_MODE)) {
return STATUS_INVALID_PARAMETER_5;
}
//
// Get a handle to the physical memory section using our pointer.
// If this fails, return.
//
ntStatus = ObOpenObjectByPointer(DeviceExtension->PhysicalMemorySection,
0L,
(PACCESS_STATE) NULL,
SECTION_ALL_ACCESS,
(POBJECT_TYPE) NULL,
KernelMode,
&physicalMemoryHandle);
if (!NT_SUCCESS(ntStatus)) {
return ntStatus;
}
#ifdef _ALPHA_
//
// All flags are necessary for translation on ALPHA, except the P6 FLAG
//
inIoSpace1 = *InIoSpace & ~VIDEO_MEMORY_SPACE_P6CACHE;
inIoSpace2 = *InIoSpace & ~VIDEO_MEMORY_SPACE_P6CACHE;
#else
//
// No flags are used in translation on non-alpha
//
inIoSpace1 = *InIoSpace & VIDEO_MEMORY_SPACE_IO;
inIoSpace2 = *InIoSpace & VIDEO_MEMORY_SPACE_IO;
#endif
//
// Initialize the physical addresses that will be translated
//
physicalAddressEnd.QuadPart = PhysicalAddress.QuadPart + (*Length - 1);
//
// Translate the physical addresses.
//
translateBaseAddress =
HalTranslateBusAddress(DeviceExtension->AdapterInterfaceType,
DeviceExtension->SystemIoBusNumber,
PhysicalAddress,
&inIoSpace1,
&physicalAddressBase);
translateEndAddress =
HalTranslateBusAddress(DeviceExtension->AdapterInterfaceType,
DeviceExtension->SystemIoBusNumber,
physicalAddressEnd,
&inIoSpace2,
&physicalAddressEnd);
if ( !(translateBaseAddress && translateEndAddress) ) {
ZwClose(physicalMemoryHandle);
return STATUS_DEVICE_CONFIGURATION_ERROR;
}
ASSERT(inIoSpace1 == inIoSpace2);
//
// Calcualte the length of the memory to be mapped
//
mappedLength.QuadPart = physicalAddressEnd.QuadPart -
physicalAddressBase.QuadPart + 1;
pVideoDebugPrint((3, "mapped Length = %x\n", mappedLength));
#ifndef _ALPHA_
//
// On all systems except ALPHA the mapped length should be the same as
// the translated length.
//
ASSERT (mappedLength.LowPart == *Length);
#endif
//
// If the mappedlength is zero, somthing very weird happened in the HAL
// since the Length was checked against zero.
//
ASSERT (mappedLength.LowPart != 0);
*Length = mappedLength.LowPart;
//
// If the address is in io space, just return the address, otherwise
// go through the mapping mechanism
//
if ( (*InIoSpace) & (ULONG)0x01 ) {
(ULONG) *VirtualAddress = physicalAddressBase.LowPart;
} else {
//
// If no process handle was passed, get the handle to the current
// process.
//
if (ProcessHandle) {
processHandle = ProcessHandle;
} else {
processHandle = NtCurrentProcess();
}
//
// initialize view base that will receive the physical mapped
// address after the MapViewOfSection call.
//
viewBase = physicalAddressBase;
//
// Map the section
//
//
// BUGBUG - what to do with already cached memory ???
//
ntStatus = ZwMapViewOfSection(physicalMemoryHandle,
processHandle,
VirtualAddress,
0L,
*Length,
&viewBase,
Length,
ViewUnmap,
0,
PAGE_READWRITE | PAGE_NOCACHE);
//
// Close the handle since we only keep the pointer reference to the
// section.
//
ZwClose(physicalMemoryHandle);
//
// Mapping the section above rounded the physical address down to the
// nearest 64 K boundary. Now return a virtual address that sits where
// we wnat by adding in the offset from the beginning of the section.
//
(ULONG) *VirtualAddress += (ULONG)physicalAddressBase.LowPart -
(ULONG)viewBase.LowPart;
}
#ifdef _ALPHA_
//
// Return the proper set of modified flags.
//
*InIoSpace = inIoSpace1 | *InIoSpace & VIDEO_MEMORY_SPACE_P6CACHE;
#else
//
// Restore all the other FLAGS
// BUGBUG P6 flag may be affected !!
//
*InIoSpace = inIoSpace1 | *InIoSpace & ~VIDEO_MEMORY_SPACE_IO;
#endif
return ntStatus;
} // end pVideoPortMapUserPhysicalMem()
VP_STATUS
VideoPortMapBankedMemory(
PVOID HwDeviceExtension,
PHYSICAL_ADDRESS PhysicalAddress,
PULONG Length,
PULONG InIoSpace,
PVOID *VirtualAddress,
ULONG BankLength,
UCHAR ReadWriteBank,
PBANKED_SECTION_ROUTINE BankRoutine,
PVOID Context
)
/*++
Routine Description:
VideoPortMapMemory allows the miniport driver to map a section of
physical memory (either memory or registers) into the calling process'
address space (eventhough we are in kernel mode, this function is
executed within the same context as the user-mode process that initiated
the call).
Arguments:
HwDeviceExtension - Points to the miniport driver's device extension.
PhysicalAddress - Specifies the physical address to be mapped.
Length - Points to the number of bytes of physical memory to be mapped.
This argument returns the actual amount of memory mapped.
InIoSpace - Points to a variable that is 1 if the address is in I/O
space. Otherwise, the address is assumed to be in memory space.
VirtualAddress - A pointer to a location containing:
on input: An optional handle to the process in which the memory must
be mapped. 0 must be used to map the memory for the display
driver (in the context of the windows server process).
on output: The return value is the virtual address at which the
physical address has been mapped.
BankLength - Size of the bank on the device.
ReadWriteBank - TRUE is the bank is READ\WRITE, FALSE if there are
two independent READ and WRITE banks.
BankRoutine - Pointer to the banking routine.
Context - Context parameter passed in by the miniport supplied on
each callback to the miniport.
Return Value:
VideoPortMapBankedMemory returns the status of the operation.
Environment:
This routine cannot be called from a miniport routine synchronized with
VideoPortSynchronizeRoutine or from an ISR.
--*/
{
VP_STATUS status;
HANDLE processHandle;
//
// Save the process ID, but don't change it since MapMemory relies
// on it also
//
if (*VirtualAddress == NULL) {
processHandle = NtCurrentProcess();
} else {
processHandle = (HANDLE) *VirtualAddress;
}
status = VideoPortMapMemory(HwDeviceExtension,
PhysicalAddress,
Length,
InIoSpace,
VirtualAddress);
if (status == NO_ERROR) {
NTSTATUS ntstatus;
ntstatus = MmSetBankedSection(processHandle,
*VirtualAddress,
BankLength,
ReadWriteBank,
BankRoutine,
Context);
if (!NT_SUCCESS(ntstatus)) {
ASSERT (FALSE);
status = ERROR_INVALID_PARAMETER;
}
}
return status;
} // end VideoPortMapBankedMemory()
VP_STATUS
VideoPortMapMemory(
PVOID HwDeviceExtension,
PHYSICAL_ADDRESS PhysicalAddress,
PULONG Length,
PULONG InIoSpace,
PVOID *VirtualAddress
)
/*++
Routine Description:
VideoPortMapMemory allows the miniport driver to map a section of
physical memory (either memory or registers) into the calling process'
address space (eventhough we are in kernel mode, this function is
executed within the same context as the user-mode process that initiated
the call).
Arguments:
HwDeviceExtension - Points to the miniport driver's device extension.
PhysicalAddress - Specifies the physical address to be mapped.
Length - Points to the number of bytes of physical memory to be mapped.
This argument returns the actual amount of memory mapped.
InIoSpace - Points to a variable that is 1 if the address is in I/O
space. Otherwise, the address is assumed to be in memory space.
VirtualAddress - A pointer to a location containing:
on input: An optional handle to the process in which the memory must
be mapped. 0 must be used to map the memory for the display
driver (in the context of the windows server process).
on output: The return value is the virtual address at which the
physical address has been mapped.
Return Value:
VideoPortMapMemory returns the status of the operation.
Environment:
This routine cannot be called from a miniport routine synchronized with
VideoPortSynchronizeRoutine or from an ISR.
--*/
{
NTSTATUS ntStatus;
PDEVICE_EXTENSION deviceExtension =
((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
HANDLE processHandle;
//
// Check for valid pointers.
//
if (!(ARGUMENT_PRESENT(Length)) ||
!(ARGUMENT_PRESENT(InIoSpace)) ||
!(ARGUMENT_PRESENT(VirtualAddress)) ) {
ASSERT(FALSE);
return ERROR_INVALID_PARAMETER;
}
//
// Let's handle the special memory types here.
//
// NOTE
// Large pages is automatic - the caller need not specify this attribute
// since it does not affect the device.
//
// Save the process handle and zero out the Virtual address field
//
if (*VirtualAddress == NULL) {
if (*InIoSpace & VIDEO_MEMORY_SPACE_USER_MODE)
{
ASSERT(FALSE);
return ERROR_INVALID_PARAMETER;
}
pVideoDebugPrint((3, "VideoPortMapMemory: Map Physical Address %08lx\n",
PhysicalAddress));
ntStatus = STATUS_SUCCESS;
//
// We specify TRUE for large pages since we know the addrses will only
// be used in the context of the display driver, at normal IRQL.
//
*VirtualAddress = pVideoPortGetDeviceBase(HwDeviceExtension,
PhysicalAddress,
*Length,
(UCHAR) (*InIoSpace),
TRUE);
//
// Zero can only be success if the driver is calling to MAP
// address 0. Otherwise, it is an error.
// BUGBUG - is this really robust.
//
if (*VirtualAddress == NULL) {
//
// Only on X86 can the logical address also be 0.
//
#if defined (_X86_)
if (PhysicalAddress.LowPart != 0)
#endif
ntStatus = STATUS_INVALID_PARAMETER;
}
} else {
if (!(*InIoSpace & VIDEO_MEMORY_SPACE_USER_MODE))
{
//
// We can not assert since this is an existing path and old
// drivers will not have this flag set.
//
// ASSERT(FALSE);
// return ERROR_INVALID_PARAMETER;
//
*InIoSpace |= VIDEO_MEMORY_SPACE_USER_MODE;
}
processHandle = (HANDLE) *VirtualAddress;
*VirtualAddress = NULL;
pVideoDebugPrint((3, "VideoPortMapMemory: Map Physical Address %08lx\n",
PhysicalAddress));
ntStatus = pVideoPortMapUserPhysicalMem(deviceExtension,
processHandle,
PhysicalAddress,
Length,
InIoSpace,
VirtualAddress);
}
if (!NT_SUCCESS(ntStatus)) {
*VirtualAddress = NULL;
pVideoDebugPrint((0, "VideoPortMapMemory failed with NtStatus = %08lx\n",
ntStatus));
ASSERT(FALSE);
return ERROR_INVALID_PARAMETER;
} else {
pVideoDebugPrint((3, "VideoPortMapMemory succeded with Virtual Address = %08lx\n",
*VirtualAddress));
return NO_ERROR;
}
} // end VideoPortMapMemory()
//
//VOID
//VideoPortMoveMemory(
// IN PVOID Destination,
// IN PVOID Source,
// IN ULONG Length
// )
//
//Forwarded to RtlMoveMemory(Destination,Source,Length);
//
//
// ALL the functions to read ports and registers are forwarded on free
// builds on x86 and ALPHA to the appropriate kernel function.
// This saves time and memory
//
//
// BUGBUG
// Disable forwarders until we fix the problem with writting to the
// BIOS data area (which must be done in the context of CSR)
//
//
// #if (DBG || (!defined(_X86_) && !defined(_ALPHA_)))
UCHAR
VideoPortReadPortUchar(
IN PUCHAR Port
)
/*++
Routine Description:
VideoPortReadPortUchar reads a byte from the specified port address.
It requires a logical port address obtained from VideoPortGetDeviceBase.
Arguments:
Port - Specifies the port address.
Return Value:
This function returns the byte read from the specified port address.
--*/
{
UCHAR temp;
IS_ACCESS_RANGES_DEFINED()
temp = READ_PORT_UCHAR(Port);
pVideoDebugPrint((3,"VideoPortReadPortUchar %x = %x\n", Port, temp));
return(temp);
} // VideoPortReadPortUchar()
USHORT
VideoPortReadPortUshort(
IN PUSHORT Port
)
/*++
Routine Description:
VideoPortReadPortUshort reads a word from the specified port address.
It requires a logical port address obtained from VideoPortGetDeviceBase.
Arguments:
Port - Specifies the port address.
Return Value:
This function returns the word read from the specified port address.
--*/
{
USHORT temp;
IS_ACCESS_RANGES_DEFINED()
temp = READ_PORT_USHORT(Port);
pVideoDebugPrint((3,"VideoPortReadPortUshort %x = %x\n", Port, temp));
return(temp);
} // VideoPortReadPortUshort()
ULONG
VideoPortReadPortUlong(
IN PULONG Port
)
/*++
Routine Description:
VideoPortReadPortUlong reads a double word from the specified port
address. It requires a logical port address obtained from
VideoPortGetDeviceBase.
Arguments:
Port - Specifies the port address.
Return Value:
This function returns the double word read from the specified port address.
--*/
{
ULONG temp;
IS_ACCESS_RANGES_DEFINED()
temp = READ_PORT_ULONG(Port);
pVideoDebugPrint((3,"VideoPortReadPortUlong %x = %x\n", Port, temp));
return(temp);
} // VideoPortReadPortUlong()
VOID
VideoPortReadPortBufferUchar(
IN PUCHAR Port,
IN PUCHAR Buffer,
IN ULONG Count
)
/*++
Routine Description:
VideoPortReadPortBufferUchar reads a number of bytes from a single port
into a buffer. It requires a logical port address obtained from
VideoPortGetDeviceBase.
Arguments:
Port - Specifies the port address.
Buffer - Points to an array of UCHAR values into which the values are
stored.
Count - Specifes the number of bytes to be read into the buffer.
Return Value:
None.
--*/
{
pVideoDebugPrint((3,"VideoPortReadPortBufferUchar %x\n", Port));
IS_ACCESS_RANGES_DEFINED()
READ_PORT_BUFFER_UCHAR(Port, Buffer, Count);
} // VideoPortReadPortBufferUchar()
VOID
VideoPortReadPortBufferUshort(
IN PUSHORT Port,
IN PUSHORT Buffer,
IN ULONG Count
)
/*++
Routine Description:
VideoPortReadPortBufferUshort reads a number of words from a single port
into a buffer. It requires a logical port address obtained from
VideoPortGetDeviceBase.
Arguments:
Port - Specifies the port address.
Buffer - Points to an array of words into which the values are stored.
Count - Specifies the number of words to be read into the buffer.
Return Value:
None.
--*/
{
pVideoDebugPrint((3,"VideoPortReadPortBufferUshort %x\n", Port));
IS_ACCESS_RANGES_DEFINED()
READ_PORT_BUFFER_USHORT(Port, Buffer, Count);
} // VideoPortReadPortBufferUshort()
VOID
VideoPortReadPortBufferUlong(
IN PULONG Port,
IN PULONG Buffer,
IN ULONG Count
)
/*++
Routine Description:
VideoPortReadPortBufferUlong reads a number of double words from a
single port into a buffer. It requires a logical port address obtained
from VideoPortGetDeviceBase.
Arguments:
Port - Specifies the port address.
Buffer - Points to an array of double words into which the values are
stored.
Count - Specifies the number of double words to be read into the buffer.
Return Value:
None.
--*/
{
pVideoDebugPrint((3,"VideoPortReadPortBufferUlong %x\n", Port));
IS_ACCESS_RANGES_DEFINED()
READ_PORT_BUFFER_ULONG(Port, Buffer, Count);
} // VideoPortReadPortBufferUlong()
UCHAR
VideoPortReadRegisterUchar(
IN PUCHAR Register
)
/*++
Routine Description:
VideoPortReadRegisterUchar reads a byte from the specified register
address. It requires a logical port address obtained from
VideoPortGetDeviceBase.
Arguments:
Register - Specifies the register address.
Return Value:
This function returns the byte read from the specified register address.
--*/
{
UCHAR temp;
IS_ACCESS_RANGES_DEFINED()
if (((ULONG)Register < 0x00100000) && CsrProcess) {
KeAttachProcess(&CsrProcess->Pcb);
}
temp = READ_REGISTER_UCHAR(Register);
if (((ULONG)Register < 0x00100000) && CsrProcess) {
KeDetachProcess();
}
pVideoDebugPrint((3,"VideoPortReadRegisterUchar %x = %x\n", Register, temp));
return(temp);
} // VideoPortReadRegisterUchar()
USHORT
VideoPortReadRegisterUshort(
IN PUSHORT Register
)
/*++
Routine Description:
VideoPortReadRegisterUshort reads a word from the specified register
address. It requires a logical port address obtained from
VideoPortGetDeviceBase.
Arguments:
Register - Specifies the register address.
Return Value:
This function returns the word read from the specified register address.
--*/
{
USHORT temp;
IS_ACCESS_RANGES_DEFINED()
if (((ULONG)Register < 0x00100000) && CsrProcess) {
KeAttachProcess(&CsrProcess->Pcb);
}
temp = READ_REGISTER_USHORT(Register);
if (((ULONG)Register < 0x00100000) && CsrProcess) {
KeDetachProcess();
}
pVideoDebugPrint((3,"VideoPortReadRegisterUshort %x = %x\n", Register, temp));
return(temp);
} // VideoPortReadRegisterUshort()
ULONG
VideoPortReadRegisterUlong(
IN PULONG Register
)
/*++
Routine Description:
VideoPortReadRegisterUlong reads a double word from the specified
register address. It requires a logical port address obtained from
VideoPortGetDeviceBase.
Arguments:
Register - Specifies the register address.
Return Value:
This function returns the double word read from the specified register
address.
--*/
{
ULONG temp;
IS_ACCESS_RANGES_DEFINED()
if (((ULONG)Register < 0x00100000) && CsrProcess) {
KeAttachProcess(&CsrProcess->Pcb);
}
temp = READ_REGISTER_ULONG(Register);
if (((ULONG)Register < 0x00100000) && CsrProcess) {
KeDetachProcess();
}
pVideoDebugPrint((3,"VideoPortReadRegisterUlong %x = %x\n", Register, temp));
return(temp);
} // VideoPortReadRegisterUlong()
VOID
VideoPortReadRegisterBufferUchar(
IN PUCHAR Register,
IN PUCHAR Buffer,
IN ULONG Count
)
/*++
Routine Description:
Read a buffer of unsigned bytes from the specified register address.
Arguments:
Register - Supplies a pointer to the port address.
Buffer - Supplies a pointer to the data buffer area.
Count - The count of items to move.
Return Value:
None
--*/
{
IS_ACCESS_RANGES_DEFINED()
if (((ULONG)Register < 0x00100000) && CsrProcess) {
KeAttachProcess(&CsrProcess->Pcb);
}
READ_REGISTER_BUFFER_UCHAR(Register, Buffer, Count);
if (((ULONG)Register < 0x00100000) && CsrProcess) {
KeDetachProcess();
}
}
VOID
VideoPortReadRegisterBufferUshort(
IN PUSHORT Register,
IN PUSHORT Buffer,
IN ULONG Count
)
/*++
Routine Description:
Read a buffer of unsigned shorts from the specified register address.
Arguments:
Register - Supplies a pointer to the port address.
Buffer - Supplies a pointer to the data buffer area.
Count - The count of items to move.
Return Value:
None
--*/
{
IS_ACCESS_RANGES_DEFINED()
if (((ULONG)Register < 0x00100000) && CsrProcess) {
KeAttachProcess(&CsrProcess->Pcb);
}
READ_REGISTER_BUFFER_USHORT(Register, Buffer, Count);
if (((ULONG)Register < 0x00100000) && CsrProcess) {
KeDetachProcess();
}
}
VOID
VideoPortReadRegisterBufferUlong(
IN PULONG Register,
IN PULONG Buffer,
IN ULONG Count
)
/*++
Routine Description:
Read a buffer of unsigned longs from the specified register address.
Arguments:
Register - Supplies a pointer to the port address.
Buffer - Supplies a pointer to the data buffer area.
Count - The count of items to move.
Return Value:
None
--*/
{
IS_ACCESS_RANGES_DEFINED()
if (((ULONG)Register < 0x00100000) && CsrProcess) {
KeAttachProcess(&CsrProcess->Pcb);
}
READ_REGISTER_BUFFER_ULONG(Register, Buffer, Count);
if (((ULONG)Register < 0x00100000) && CsrProcess) {
KeDetachProcess();
}
}
// #endif // (DBG || (!defined(_X86_) && !defined(_ALPHA_)))
BOOLEAN
pVideoPortResetDisplay(
IN ULONG Columns,
IN ULONG Rows
)
/*++
Routine Description:
Callback for the HAL that calls the miniport driver.
Arguments:
Columns - The number of columns of the video mode.
Rows - The number of rows for the video mode.
Return Value:
We always return FALSE so the HAL will always reste the mode afterwards.
Environment:
Non-paged only.
Used in BugCheck and soft-reset calls.
--*/
{
if (HwResetHw[0].ResetFunction) {
return (HwResetHw[0].ResetFunction(HwResetHw[0].HwDeviceExtension,
Columns,
Rows));
} else {
return FALSE;
}
} // end pVideoPortResetDisplay()
BOOLEAN
VideoPortScanRom(
PVOID HwDeviceExtension,
PUCHAR RomBase,
ULONG RomLength,
PUCHAR String
)
/*++
Routine Description:
Does a case *SENSITIVE* search for a string in the ROM.
Arguments:
HwDeviceExtension - Points to the miniport driver's device extension.
RomBase - Base address at which the search should start.
RomLength - Size, in bytes, of the ROM area in which to perform the
search.
String - String to search for
Return Value:
Returns TRUE if the string was found.
Returns FALSE if it was not found.
Environment:
This routine cannot be called from a miniport routine synchronized with
VideoPortSynchronizeRoutine or from an ISR.
--*/
{
ULONG stringLength, length;
ULONG startOffset;
PUCHAR string1, string2;
BOOLEAN match;
UNREFERENCED_PARAMETER(HwDeviceExtension);
stringLength = strlen(String);
for (startOffset = 0;
startOffset < RomLength - stringLength + 1;
startOffset++) {
length = stringLength;
string1 = RomBase + startOffset;
string2 = String;
match = TRUE;
IS_ACCESS_RANGES_DEFINED()
while (length--) {
if (READ_REGISTER_UCHAR(string1++) - (*string2++)) {
match = FALSE;
break;
}
}
if (match) {
return TRUE;
}
}
return FALSE;
} // end VideoPortScanRom()
ULONG
VideoPortSetBusData(
PVOID HwDeviceExtension,
IN BUS_DATA_TYPE BusDataType,
IN ULONG SlotNumber,
IN PVOID Buffer,
IN ULONG Offset,
IN ULONG Length
)
{
PDEVICE_EXTENSION deviceExtension =
deviceExtension = ((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
return HalSetBusDataByOffset(BusDataType,
deviceExtension->SystemIoBusNumber,
SlotNumber,
Buffer,
Offset,
Length);
} // end VideoPortSetBusData()
VP_STATUS
VideoPortSetRegistryParameters(
PVOID HwDeviceExtension,
PWSTR ValueName,
PVOID ValueData,
ULONG ValueLength
)
/*++
Routine Description:
VideoPortSetRegistryParameters writes information to the CurrentControlSet
in the registry. The function automatically searches for or creates the
specified parameter name under the parameter key of the current driver.
Arguments:
HwDeviceExtension - Points to the miniport driver's device extension.
ValueName - Points to a Unicode string that contains the name of the
data value being written in the registry.
ValueData - Points to a buffer containing the information to be written
to the registry.
ValueLength - Specifies the size of the data being written to the registry.
Return Value:
This function returns the final status of the operation.
Environment:
This routine cannot be called from a miniport routine synchronized with
VideoPortSynchronizeRoutine or from an ISR.
--*/
{
NTSTATUS ntStatus;
PDEVICE_EXTENSION deviceExtension =
((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
//
// BUGBUG What will happen if the value does not already exist ?
//
//
// BUGBUG What happens for files ... ?
//
ntStatus = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
deviceExtension->DriverRegistryPath,
ValueName,
REG_BINARY,
ValueData,
ValueLength);
if (!NT_SUCCESS(ntStatus)) {
return ERROR_INVALID_PARAMETER;
} else {
return NO_ERROR;
}
} // end VideoPortSetRegistryParamaters()
VOID
pVideoPortHwTimer(
IN PDEVICE_OBJECT DeviceObject,
PVOID Context
)
/*++
Routine Description:
This function is the main entry point for the timer routine that we then
forward to the miniport driver.
Arguments:
DeviceObject -
Context - Not needed
Return Value:
None.
--*/
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
UNREFERENCED_PARAMETER(Context);
deviceExtension->HwTimer(deviceExtension->HwDeviceExtension);
return;
} // pVideoPortInterrupt()
VOID
VideoPortStartTimer(
PVOID HwDeviceExtension
)
/*++
Routine Description:
Enables the timer specified in the HW_INITIALIZATION_DATA structure
passed to the video port driver at init time.
Arguments:
HwDeviceExtension - Points to the miniport driver's device extension.
Return Value:
None
--*/
{
PDEVICE_EXTENSION deviceExtension =
((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
if (deviceExtension->HwTimer == NULL) {
ASSERT(deviceExtension->HwTimer != NULL);
} else {
IoStartTimer(deviceExtension->DeviceObject);
}
return;
}
VOID
VideoPortStopTimer(
PVOID HwDeviceExtension
)
/*++
Routine Description:
Disables the timer specified in the HW_INITIALIZATION_DATA structure
passed to the video port driver at init time.
Arguments:
HwDeviceExtension - Points to the miniport driver's device extension.
Return Value:
None
--*/
{
PDEVICE_EXTENSION deviceExtension =
((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
if (deviceExtension->HwTimer == NULL) {
ASSERT(deviceExtension->HwTimer != NULL);
} else {
IoStopTimer(deviceExtension->DeviceObject);
}
return;
}
//
//VOID
//VideoPortStallExecution(
// IN ULONG Microseconds
// )
//
//Forwarded to KeStallExecutionProcessor(Microseconds);
//
BOOLEAN
VideoPortSynchronizeExecution(
PVOID HwDeviceExtension,
VIDEO_SYNCHRONIZE_PRIORITY Priority,
PMINIPORT_SYNCHRONIZE_ROUTINE SynchronizeRoutine,
PVOID Context
)
/*++
Stub so we can allow the miniports to link directly
--*/
{
return pVideoPortSynchronizeExecution(HwDeviceExtension,
Priority,
SynchronizeRoutine,
Context);
} // end VideoPortSynchronizeExecution()
BOOLEAN
pVideoPortSynchronizeExecution(
PVOID HwDeviceExtension,
VIDEO_SYNCHRONIZE_PRIORITY Priority,
PMINIPORT_SYNCHRONIZE_ROUTINE SynchronizeRoutine,
PVOID Context
)
/*++
Routine Description:
VideoPortSynchronizeExecution synchronizes the execution of a miniport
driver function in the following manner:
- If Priority is equal to VpLowPriority, the current thread is
raised to the highest non-interrupt-masking priority. In
other words, the current thread can only be pre-empted by an ISR.
- If Priority is equal to VpMediumPriority and there is an
ISR associated with the video device, then the function specified
by SynchronizeRoutine is synchronized with the ISR.
If no ISR is connected, synchronization is made at VpHighPriority
level.
- If Priority is equal to VpHighPriority, the current IRQL is
raised to HIGH_LEVEL, which effectively masks out ALL interrupts
in the system. This should be done sparingly and for very short
periods -- it will completely freeze up the entire system.
Arguments:
HwDeviceExtension - Points to the miniport driver's device extension.
Priority - Specifies the type of priority at which the SynchronizeRoutine
must be executed (found in VIDEO_SYNCHRONIZE_PRIORITY).
SynchronizeRoutine - Points to the miniport driver function to be
synchronized.
Context - Specifies a context parameter to be passed to the miniport's
SynchronizeRoutine.
Return Value:
This function returns TRUE if the operation is successful. Otherwise, it
returns FALSE.
--*/
{
BOOLEAN status;
PDEVICE_EXTENSION deviceExtension =
((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
KIRQL oldIrql;
//
// Switch on which type of priority.
//
switch (Priority) {
case VpMediumPriority:
//
// This is synchronized with the interrupt object
//
if (deviceExtension->InterruptObject) {
status = KeSynchronizeExecution(deviceExtension->InterruptObject,
(PKSYNCHRONIZE_ROUTINE)
SynchronizeRoutine,
Context);
ASSERT (status == TRUE);
return status;
}
//
// Fall through for Medium Priority
//
case VpLowPriority:
//
// Just normal lelvel
//
status = SynchronizeRoutine(Context);
break;
case VpHighPriority:
//
// This is like cli\sti where we mask out everything.
//
//
// Get the current IRQL to catch re-entrant routines into synchronize.
//
oldIrql = KeGetCurrentIrql();
if (oldIrql < POWER_LEVEL - 1) {
KeRaiseIrql(POWER_LEVEL, &oldIrql);
}
status = SynchronizeRoutine(Context);
if (oldIrql < POWER_LEVEL - 1) {
KeLowerIrql(oldIrql);
}
return status;
break;
default:
return FALSE;
}
}
VP_STATUS
VideoPortUnmapMemory(
PVOID HwDeviceExtension,
PVOID VirtualAddress,
HANDLE ProcessHandle
)
/*++
Routine Description:
VideoPortUnmapMemory allows the miniport driver to unmap a physical
address range previously mapped into the calling process' address space
using the VideoPortMapMemory function.
Arguments:
HwDeviceExtension - Points to the miniport driver's device extension.
VirtualAddress - Points to the virtual address to unmap from the
address space of the caller.
// InIoSpace - Specifies whether the address is in I/O space (1) or memory
// space (0).
ProcessHandle - Handle to the process from which memory must be unmapped.
Return Value:
This function returns a status code of NO_ERROR if the operation succeeds.
It returns ERROR_INVALID_PARAMETER if an error occurs.
Environment:
This routine cannot be called from a miniport routine synchronized with
VideoPortSynchronizeRoutine or from an ISR.
--*/
{
NTSTATUS ntstatus;
VP_STATUS vpStatus = NO_ERROR;
PDEVICE_EXTENSION deviceExtension =
((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
//
// Backwards compatibility to when the ProcessHandle was actually
// ULONG InIoSpace.
//
if (((ULONG)(ProcessHandle)) == 1) {
pVideoDebugPrint((0,"\n\n*** VideoPortUnmapMemory - interface change *** Must pass in process handle\n\n"));
DbgBreakPoint();
return NO_ERROR;
}
if (((ULONG)(ProcessHandle)) == 0) {
//
// If the process handle is zero, it means it was mapped by the display
// driver and is therefore in kernel mode address space.
//
if (!pVideoPortFreeDeviceBase(HwDeviceExtension, VirtualAddress)) {
ASSERT(FALSE);
vpStatus = ERROR_INVALID_PARAMETER;
}
} else {
//
// A process handle is passed in.
// This ms it was mapped for use by an application (DCI \ DirectDraw).
//
#ifdef _ALPHA_
//
// On Alpha, VirtualAddress may not be a true VA if this was
// a sparse memory or IO space. Transform the QVA to a VA,
// if necessary.
//
VirtualAddress = HalDereferenceQva(VirtualAddress,
deviceExtension->AdapterInterfaceType,
deviceExtension->SystemIoBusNumber);
#endif
ntstatus = ZwUnmapViewOfSection(ProcessHandle,
(PVOID) ( ((ULONG)VirtualAddress) & (~(PAGE_SIZE - 1)) ) );
if ( (!NT_SUCCESS(ntstatus)) &&
(ntstatus != STATUS_PROCESS_IS_TERMINATING) ) {
ASSERT(FALSE);
vpStatus = ERROR_INVALID_PARAMETER;
}
}
return NO_ERROR;
} // end VideoPortUnmapMemory()
//
// ALL the functions to write ports and registers are forwarded on free
// builds on x86 to the appropriate kernel function.
// This saves time and memory
//
//
// BUGBUG
// Disable forwarders until we fix the problem with writting to the
// BIOS data area (which must be done in the context of CSR)
//
//
// #if (DBG || (!defined(_X86_) && !defined(_ALPHA_)))
VOID
VideoPortWritePortUchar(
IN PUCHAR Port,
IN UCHAR Value
)
/*++
Routine Description:
VideoPortWritePortUchar writes a byte to the specified port address. It
requires a logical port address obtained from VideoPortGetDeviceBase.
Arguments:
Port - Specifies the port address.
Value - Specifies a byte to be written to the port.
Return Value:
None.
--*/
{
pVideoDebugPrint((3,"VideoPortWritePortUchar %x %x\n", Port, Value));
IS_ACCESS_RANGES_DEFINED()
WRITE_PORT_UCHAR(Port, Value);
} // VideoPortWritePortUchar()
VOID
VideoPortWritePortUshort(
IN PUSHORT Port,
IN USHORT Value
)
/*++
Routine Description:
VideoPortWritePortUshort writes a word to the specified port address. It
requires a logical port address obtained from VideoPortGetDeviceBase.
Arguments:
Port - Specifies the port address.
Value - Specifies a word to be written to the port.
Return Value:
None.
--*/
{
pVideoDebugPrint((3,"VideoPortWritePortUhort %x %x\n", Port, Value));
IS_ACCESS_RANGES_DEFINED()
WRITE_PORT_USHORT(Port, Value);
} // VideoPortWritePortUshort()
VOID
VideoPortWritePortUlong(
IN PULONG Port,
IN ULONG Value
)
/*++
Routine Description:
VideoPortWritePortUlong writes a double word to the specified port address.
It requires a logical port address obtained from VideoPortGetDeviceBase.
Arguments:
Port - Specifies the port address.
Value - Specifies a double word to be written to the port.
Return Value:
None.
--*/
{
pVideoDebugPrint((3,"VideoPortWritePortUlong %x %x\n", Port, Value));
IS_ACCESS_RANGES_DEFINED()
WRITE_PORT_ULONG(Port, Value);
} // VideoPortWritePortUlong()
VOID
VideoPortWritePortBufferUchar(
IN PUCHAR Port,
IN PUCHAR Buffer,
IN ULONG Count
)
/*++
Routine Description:
VideoPortWritePortBufferUchar writes a number of bytes to a
specific port. It requires a logical port address obtained from
VideoPortGetDeviceBase.
Arguments:
Port - Specifies the port address.
Buffer - Points to an array of bytes to be written.
Count - Specifies the number of bytes to be written to the buffer.
Return Value:
None.
--*/
{
pVideoDebugPrint((3,"VideoPortWritePortBufferUchar %x \n", Port));
IS_ACCESS_RANGES_DEFINED()
WRITE_PORT_BUFFER_UCHAR(Port, Buffer, Count);
} // VideoPortWritePortBufferUchar()
VOID
VideoPortWritePortBufferUshort(
IN PUSHORT Port,
IN PUSHORT Buffer,
IN ULONG Count
)
/*++
Routine Description:
VideoPortWritePortBufferUshort writes a number of words to a
specific port. It requires a logical port address obtained from
VideoPortGetDeviceBase.
Arguments:
Port - Specifies the port address.
Buffer - Points to an array of words to be written.
Count - Specifies the number of words to be written to the buffer.
Return Value:
None.
--*/
{
pVideoDebugPrint((3,"VideoPortWritePortBufferUshort %x \n", Port));
IS_ACCESS_RANGES_DEFINED()
WRITE_PORT_BUFFER_USHORT(Port, Buffer, Count);
} // VideoPortWritePortBufferUshort()
VOID
VideoPortWritePortBufferUlong(
IN PULONG Port,
IN PULONG Buffer,
IN ULONG Count
)
/*++
Routine Description:
VideoPortWritePortBufferUlong writes a number of double words to a
specific port. It requires a logical port address obtained from
VideoPortGetDeviceBase.
Arguments:
Port - Specifies the port address.
Buffer - Points to an array of double word to be written.
Count - Specifies the number of double words to be written to the buffer.
Return Value:
None.
--*/
{
pVideoDebugPrint((3,"VideoPortWriteBufferUlong %x \n", Port));
IS_ACCESS_RANGES_DEFINED()
WRITE_PORT_BUFFER_ULONG(Port, Buffer, Count);
} // VideoPortWritePortBufferUlong()
VOID
VideoPortWriteRegisterUchar(
IN PUCHAR Register,
IN UCHAR Value
)
/*++
Routine Description:
VideoPortWriteRegisterUchar writes a byte to the specified
register address. It requires a logical port address obtained
from VideoPortGetDeviceBase.
Arguments:
Register - Specifies the register address.
Value - Specifies a byte to be written to the register.
Return Value:
None.
--*/
{
pVideoDebugPrint((3,"VideoPortWritePortRegisterUchar %x \n", Register));
IS_ACCESS_RANGES_DEFINED()
if (((ULONG)Register < 0x00100000) && CsrProcess) {
KeAttachProcess(&CsrProcess->Pcb);
}
WRITE_REGISTER_UCHAR(Register, Value);
if (((ULONG)Register < 0x00100000) && CsrProcess) {
KeDetachProcess();
}
} // VideoPortWriteRegisterUchar()
VOID
VideoPortWriteRegisterUshort(
IN PUSHORT Register,
IN USHORT Value
)
/*++
Routine Description:
VideoPortWriteRegisterUshort writes a word to the specified
register address. It requires a logical port address obtained
from VideoPortGetDeviceBase.
Arguments:
Register - Specifies the register address.
Value - Specifies a word to be written to the register.
Return Value:
None.
--*/
{
pVideoDebugPrint((3,"VideoPortWritePortRegisterUshort %x \n", Register));
IS_ACCESS_RANGES_DEFINED()
if (((ULONG)Register < 0x00100000) && CsrProcess) {
KeAttachProcess(&CsrProcess->Pcb);
}
WRITE_REGISTER_USHORT(Register, Value);
if (((ULONG)Register < 0x00100000) && CsrProcess) {
KeDetachProcess();
}
} // VideoPortWriteRegisterUshort()
VOID
VideoPortWriteRegisterUlong(
IN PULONG Register,
IN ULONG Value
)
/*++
Routine Description:
VideoPortWriteRegisterUlong writes a double word to the
specified register address. It requires a logical port
address obtained from VideoPortGetDeviceBase.
Arguments:
Register - Specifies the register address.
Value - Specifies a double word to be written to the register.
Return Value:
None.
--*/
{
pVideoDebugPrint((3,"VideoPortWritePortRegisterUlong %x \n", Register));
IS_ACCESS_RANGES_DEFINED()
if (((ULONG)Register < 0x00100000) && CsrProcess) {
KeAttachProcess(&CsrProcess->Pcb);
}
WRITE_REGISTER_ULONG(Register, Value);
if (((ULONG)Register < 0x00100000) && CsrProcess) {
KeDetachProcess();
}
} // VideoPortWriteRegisterUlong()
VOID
VideoPortWriteRegisterBufferUchar(
IN PUCHAR Register,
IN PUCHAR Buffer,
IN ULONG Count
)
/*++
Routine Description:
Write a buffer of unsigned bytes from the specified register address.
Arguments:
Register - Supplies a pointer to the port address.
Buffer - Supplies a pointer to the data buffer area.
Count - The count of items to move.
Return Value:
None
--*/
{
IS_ACCESS_RANGES_DEFINED()
if (((ULONG)Register < 0x00100000) && CsrProcess) {
KeAttachProcess(&CsrProcess->Pcb);
}
WRITE_REGISTER_BUFFER_UCHAR(Register, Buffer, Count);
if (((ULONG)Register < 0x00100000) && CsrProcess) {
KeDetachProcess();
}
}
VOID
VideoPortWriteRegisterBufferUshort(
IN PUSHORT Register,
IN PUSHORT Buffer,
IN ULONG Count
)
/*++
Routine Description:
Write a buffer of unsigned shorts from the specified register address.
Arguments:
Register - Supplies a pointer to the port address.
Buffer - Supplies a pointer to the data buffer area.
Count - The count of items to move.
Return Value:
None
--*/
{
IS_ACCESS_RANGES_DEFINED()
if (((ULONG)Register < 0x00100000) && CsrProcess) {
KeAttachProcess(&CsrProcess->Pcb);
}
WRITE_REGISTER_BUFFER_USHORT(Register, Buffer, Count);
if (((ULONG)Register < 0x00100000) && CsrProcess) {
KeDetachProcess();
}
}
VOID
VideoPortWriteRegisterBufferUlong(
IN PULONG Register,
IN PULONG Buffer,
IN ULONG Count
)
/*++
Routine Description:
Write a buffer of unsigned longs from the specified register address.
Arguments:
Register - Supplies a pointer to the port address.
Buffer - Supplies a pointer to the data buffer area.
Count - The count of items to move.
Return Value:
None
--*/
{
IS_ACCESS_RANGES_DEFINED()
if (((ULONG)Register < 0x00100000) && CsrProcess) {
KeAttachProcess(&CsrProcess->Pcb);
}
WRITE_REGISTER_BUFFER_ULONG(Register, Buffer, Count);
if (((ULONG)Register < 0x00100000) && CsrProcess) {
KeDetachProcess();
}
}
// #endif
//
//VOID
//VideoPortZeroMemory(
// IN PVOID Destination,
// IN ULONG Length
// )
//
//Forwarded to RtlZeroMemory(Destination,Length);
//
//
// DMA specific support
//
ULONG
pDumpDmaParameters(
PDMA_PARAMETERS pDMA,
ULONG LineNumber
)
{
pVideoDebugPrint((VIDEO_DMA_DUMP_DPARAMS, "At line %d, pDMA is %x\n", LineNumber, pDMA));
pVideoDebugPrint((VIDEO_DMA_DUMP_DPARAMS, "DEVICE_EXTENSION :%x\n", pDMA->pDE));
pVideoDebugPrint((VIDEO_DMA_DUMP_DPARAMS, "pVideoRequestBlock :%x\n", pDMA->pVideoRequestBlock ));
pVideoDebugPrint((VIDEO_DMA_DUMP_DPARAMS, "DataOffset :%x\n", pDMA->DataOffset ));
pVideoDebugPrint((VIDEO_DMA_DUMP_DPARAMS, "VRBFlags :%x\n", pDMA->VRBFlags ));
pVideoDebugPrint((VIDEO_DMA_DUMP_DPARAMS, "pMapRegisterBase :%x\n", pDMA->pMapRegisterBase ));
pVideoDebugPrint((VIDEO_DMA_DUMP_DPARAMS, "NumberOfMapRegisters :%x\n", pDMA->NumberOfMapRegisters ));
pVideoDebugPrint((VIDEO_DMA_DUMP_DPARAMS, "pLogicalAddress :%x\n", pDMA->pLogicalAddress ));
pVideoDebugPrint((VIDEO_DMA_DUMP_DPARAMS, "MdlAddress :%x\n", pDMA->MdlAddress ));
pVideoDebugPrint((VIDEO_DMA_DUMP_DPARAMS, "pScatterGather :%x\n", pDMA->pScatterGather ));
return 0;
}
ULONG
pDumpRequestBlock(
PVIDEO_DMA_REQUEST_BLOCK pVDRB,
ULONG LineNumber
)
{
pVideoDebugPrint((VIDEO_DMA_DUMP_REQBLOCK, "At line %d, pVDRB is %x\n", LineNumber, pVDRB));
pVideoDebugPrint((VIDEO_DMA_DUMP_REQBLOCK, "VRBFlags : %x\n", pVDRB->VRBFlags ));
pVideoDebugPrint((VIDEO_DMA_DUMP_REQBLOCK, "pDma : %x\n", pVDRB->pDma ));
pVideoDebugPrint((VIDEO_DMA_DUMP_REQBLOCK, "vrp.IoControlCode : %x\n", pVDRB->vrp.IoControlCode ));
return 0;
}
BOOLEAN
pVideoPortStartDmaSynchronized (
PVOID ServiceContext
)
/*++
Routine Description:
This routine calls the dependent driver start io routine. The context
passed in is a PDMA_PARAMETER. It references both the PDEVICE_EXTENSION
and the PVIDEO_DMA_REQUEST_BLOCK, the latter of which resides on the
dispatch routines stack. This is a synchronous call. Currently, the
DmaDeviceEvent is unsupported.
Arguments:
ServiceContext - Supplies the pointer to the device object.
Return Value:
Returns the value returned by the dependent start I/O routine.
Notes:
The port driver spinlock must be held when this routine is called.
--*/
{
PDMA_PARAMETERS pIoVrb = ServiceContext;
PDEVICE_EXTENSION deviceExtension = pIoVrb->pDE;
PVIDEO_DMA_REQUEST_BLOCK pVDRB;
BOOLEAN timerStarted;
BOOLEAN returnValue;
VideoPortDebugPrint(VIDEO_DMA_START,
"pVideoPortStartDmaSynchronized: pIoVrb:%x\n",
pIoVrb);
pVDRB = pIoVrb->pVideoRequestBlock;
pDumpDmaParameters(pIoVrb, __LINE__);
pDumpRequestBlock(pVDRB, __LINE__);
VideoPortDebugPrint(VIDEO_DMA_START,
"pVideoPortStartDmaSynchronized: pVDRB:%x\n",
pVDRB);
//
// Mark the pVDRB as active.
//
pVDRB->VRBFlags |= VRB_FLAGS_IS_ACTIVE;
returnValue = deviceExtension->HwStartDma(deviceExtension->HwDeviceExtension,
&(pVDRB->vrp));
/*
if (returnValue == DmaAsyncReturn && pVDRB->vrp.pDeviceEvent) {
KeWaitForSingleObject((PKEVENT)pVDRB->vrp.pDeviceEvent,
Executive,
KernelMode,
FALSE,
(PTIME)NULL);
pVideoDmaProcessCompletedRequest(deviceExtension, pIoVrb);
}
*/
/*
if (pVDRB->vrp.pDispDrvrEvent) {
KeSetEvent((PKEVENT)pVDRB->vrp.pDispDrvrEvent, 0, FALSE);
}
//
// Check for miniport work requests.
//
VideoPortDebugPrint(VIDEO_DMA_START,
"pVideoPortStartDmaSynchronized: deviceExtension->pInterruptContext:%x\n",
deviceExtension->pInterruptContext);
if (deviceExtension->pInterruptContext->InterruptFlags & NOTIFY_REQUIRED) {
VideoPortDebugPrint(VIDEO_DMA_START,
"pVideoPortStartDmaSynchronized: requested DPC?\n");
IoRequestDpc(deviceExtension->DeviceObject, NULL, NULL);
}
*/
return returnValue;
} // end pVideoPortStartDmaSynchronized()
IO_ALLOCATION_ACTION
pVideoPortBuildScatterGather(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP pIrp,
IN PVOID MapRegisterBase,
IN PVOID Context
)
/*++
Routine Description:
This function is called by the I/O system when an adapter object and map
registers have been allocated. This routine then builds a scatter/gather
list for use by the miniport driver. As the list is built, the registers
are mapped by calling IoMapTransfer, whose return is put into the
PhysicalAddress field of the VRB_SG.
The context is again a PDMA_PARAMETERS, which refers to an irp via the
PVIDEO_DMA_REQUEST_BLOCK and the Irp passed by in the Io subsystem is
overwritten.
Arguments:
DeviceObject - Supplies a pointer to the port driver device object.
pIrp - Supplies a pointer to the current Irp set by Io subsystem, but
unused.
MapRegisterBase - Supplies a context pointer to be used with calls the
adapter object routines.
Context - Supplies a pointer to the PDMA_PARAMETERS data structure.
Return Value:
Returns DeallocateObjectKeepRegisters so that the adapter object can be
used by other logical units.
--*/
{
PDMA_PARAMETERS pIoVrb = Context;
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
BOOLEAN writeToDevice;
PVIDEO_DMA_REQUEST_BLOCK pVDRB;
PVRB_SG pScatterList;
PCCHAR dataVirtualAddress;
ULONG totalLength;
PMDL pMdl;
pDumpDmaParameters(pIoVrb, __LINE__);
pVDRB = pIoVrb->pVideoRequestBlock;
pDumpRequestBlock(pVDRB, __LINE__);
//
// Determine if scatter/gather list must come from pool.
//
if (pIoVrb->NumberOfMapRegisters > 17) {
//
// Allocate scatter/gather list from pool.
//
pIoVrb->pScatterGather =
ExAllocatePool(NonPagedPool,
pIoVrb->NumberOfMapRegisters * sizeof(VRB_SG));
if (pIoVrb->pScatterGather == NULL) {
//
// Beyond the point of return.
//
pIoVrb->pScatterGather =
ExAllocatePool(NonPagedPoolMustSucceed,
pIoVrb->NumberOfMapRegisters * sizeof(VRB_SG));
}
//
// Indicate scatter gather list came from pool.
//
pIoVrb->VRBFlags |= VRB_FLAGS_SGLIST_FROM_POOL;
pVideoDebugPrint((VIDEO_DMA_PARAMS, "Allocated pScatterGather\n"));
} else {
//
// Use embedded scatter/gather list.
//
pIoVrb->pScatterGather = pIoVrb->SGList;
pVideoDebugPrint((VIDEO_DMA_PARAMS, "Used embedded list\n"));
}
pScatterList = pIoVrb->pScatterGather;
totalLength = 0;
//
// Determine the virtual address of the buffer for the Io map transfers.
//
dataVirtualAddress = (PCCHAR)MmGetMdlVirtualAddress((PMDL)pIoVrb->MdlAddress) +
((PCCHAR)pVDRB->vrp.InputBuffer - pIoVrb->DataOffset);
//
// Save the MapRegisterBase for later use to deallocate the map registers.
//
pIoVrb->pMapRegisterBase = MapRegisterBase;
//
// Build the scatter/gather list by looping throught the transfer calling
// I/O map transfer.
//
VideoPortDebugPrint(VIDEO_DMA_BUILD_SG,
"totalLength:%d, InputBufferLength:%d\n",
totalLength, pVDRB->vrp.InputBufferLength);
while (totalLength < pVDRB->vrp.InputBufferLength) {
//
// Request that the rest of the transfer be mapped.
//
pScatterList->Length = pVDRB->vrp.InputBufferLength - totalLength;
//
// Wacky deal: call IoMapTransfer with NULL PADAPTER_OBJECT to just
// get the physical addresses.
//
VideoPortDebugPrint(VIDEO_DMA_BUILD_SG,
"BuildSG, about to call IoMapTransfer\n");
VideoPortDebugPrint(VIDEO_DMA_BUILD_SG,
"pIoVrb->MdlAddress: %x\n",
pIoVrb->MdlAddress);
VideoPortDebugPrint(VIDEO_DMA_BUILD_SG,
"MapRegisterBase: %x\n",
MapRegisterBase);
VideoPortDebugPrint(VIDEO_DMA_BUILD_SG,
"dataVirtualAddress + totalLength: %x\n",
dataVirtualAddress + totalLength);
VideoPortDebugPrint(VIDEO_DMA_BUILD_SG,
"pScatterList:%x\n",
pScatterList);
pScatterList->PhysicalAddress = IoMapTransfer(
NULL,
pIoVrb->MdlAddress,
MapRegisterBase,
MmGetMdlVirtualAddress((PMDL)pIoVrb->MdlAddress)/*dataVirtualAddress + totalLength*/,
&(pScatterList->Length),
TRUE).LowPart;
VideoPortDebugPrint(VIDEO_DMA_BUILD_SG,
"IoMapTransfer returned PHYSADDR:%x\n", pScatterList->PhysicalAddress );
totalLength += pScatterList->Length;
pScatterList++;
}
//
// Signal VideoPortDoDma that the list is built.
//
KeSetEvent(&(pIoVrb->IoAllocEvent), 0, FALSE);
return(DeallocateObjectKeepRegisters);
}
BOOLEAN
pVideoPortReleaseDmaParameters(
PVIDEO_DMA_REQUEST_BLOCK pVDRB,
PVOID pDmaParams
)
/*++
Routine Description:
This function is called when a DMA request is complete. It walks the
list of DMA_PARAMETERS hanging off the DEVICE_EXTENSION looking for
the second argument. If found, it frees the associated DmaAdapterObject,
marks that entry as available for use and returns TRUE. If not found,
it returns FALSE.
Arguments:
Return Value:
Returns DeallocateObjectKeepRegisters so that the adapter object can be
used by other logical units.
--*/
{
PDMA_PARAMETERS pDmaParameters = (PDMA_PARAMETERS)pDmaParams;
BOOLEAN returnval = TRUE;
VideoPortDebugPrint(VIDEO_DMA_PARAMS, "Releasing %x\n", pDmaParameters);
pDmaParameters->pVideoRequestBlock->pDma = (PDMA_PARAMETERS) NULL;
pDmaParameters->pVideoRequestBlock = NULL;
pDmaParameters->pScatterGather = NULL;
pDmaParameters->NumberOfMapRegisters = 0;
if (pVDRB->pDma != pDmaParameters)
returnval = FALSE;
else
pVDRB->pDma = (PDMA_PARAMETERS)NULL;
return returnval;
}
PDMA_PARAMETERS
pVideoPortGetDmaParameters(
PDEVICE_EXTENSION deviceExtension,
PVIDEO_DMA_REQUEST_BLOCK pVDRB
)
/*++
Routine Description:
This function is called when a DMA request is started. It walks the
list of DMA_PARAMETERS hanging off the DEVICE_EXTENSION looking for
the a free node. If found, it fills that entry, marks it as not available
and returns that node. If not found, it returns NULL.
Arguments:
Return Value:
Returns a PDMA_PARAMETERS.
--*/
{
PDMA_PARAMETERS pDmaParameters = NULL;
ULONG qindex;
//
// If the pVDRB has a PDMA_PARAMETER already, reuse that DMA_PARAMETER
//
if (pVDRB->pDma != NULL) {
pVideoDebugPrint((VIDEO_DMA_PARAMS,
"pVideoPortGetDmaParameters, OLD pDma is %x in %x\n",
pVDRB->pDma, pVDRB));
pDmaParameters = pVDRB->pDma;
goto DONE;
} else {
//
// Otherwise, this may be a new public request that requires
// Io subsystem requests. So try to find an unused one, indicated
// by the pointer to the owning PVIDEO_DMA_REQUEST_BLOCK.
//
for (qindex = 0; qindex < deviceExtension->MaxQ; ++qindex) {
if (!(deviceExtension->FreeDmaParameters[qindex].pVideoRequestBlock)) {
pVideoDebugPrint((VIDEO_DMA_PARAMS,
"pVideoPortGetDmaParameters, NEW qindex is %d \n",
qindex));
pDmaParameters = &(deviceExtension->FreeDmaParameters[qindex]);
pDmaParameters->pVideoRequestBlock = pVDRB;
pVDRB->pDma = pDmaParameters;
goto DONE;
}
}
pDmaParameters = NULL;
pVDRB->vrp.StatusBlock->Status |= VRB_QUEUE_FULL;
pVideoDebugPrint((VIDEO_DMA_PARAMS,
"pVideoPortGetDmaParameters, FAILED!!!!!!\n"));
}
DONE:
return pDmaParameters;
}
VP_STATUS
pVideoPortUnlockPages(
PDEVICE_EXTENSION pDE,
PDMA_PARAMETERS pIoVrb
)
/*++
Routine Description:
This function is called when a display driver calls IoControl with
IOCTL_VIDEO_DMA_UNLOCK pages or when the completion request notices
that the bUnlock flag is set in the PVRB. It extracts the PMDL from
the PDMA_PARAMETERS and calls MmUnlock on that.
Arguments:
pDE - a pointer to the DEVICE_EXTENSION
pIoVrb - a pointer to the associated DMA_PARAMETERS.
Return Value:
VOID.
--*/
{
PVIDEO_DMA_REQUEST_BLOCK pVDRB = pIoVrb->pVideoRequestBlock;
PMDL pMdl = pIoVrb->MdlAddress;
//
// Unlock
//
pVideoDebugPrint((VIDEO_DMA_LOCK, "Unlocking:%x\n", pMdl));
MmUnlockPages(pMdl);
//
// Free Mdls
//
pVideoDebugPrint((VIDEO_DMA_LOCK, "Freeing:%x\n", pMdl));
IoFreeMdl(pMdl);
pIoVrb->MdlAddress = NULL;
//
// Free Scattergather list if indicated and clear flag.
//
if (pIoVrb->VRBFlags & VRB_FLAGS_SGLIST_FROM_POOL) {
ExFreePool(pIoVrb->pScatterGather);
pVideoDebugPrint((VIDEO_DMA_PARAMS, "Freed pScatterGather\n"));
pIoVrb->VRBFlags &= ~VRB_FLAGS_SGLIST_FROM_POOL;
}
/*
ExFreePool(pVDRB->vrp.pDeviceEvent);
*/
pVDRB->vrp.pDeviceEvent = NULL;
return NO_ERROR;
}
/*
* BUGBUG: need to provide a mechanism to miniport so it can determine when
* to free the map registers, unlock the pages, etc.
*/
VP_STATUS
pVideoDmaProcessCompletedRequest(
PDEVICE_EXTENSION pDE,
PDMA_PARAMETERS pIoVrb
)
{
PVIDEO_DMA_REQUEST_BLOCK pVDRB = pIoVrb->pVideoRequestBlock;
PVOID pMdlVirt = MmGetMdlVirtualAddress(
(PMDL)pIoVrb->MdlAddress);
//
// Map the buffers if indicated and flush.
//
if ((pDE->bMapBuffers) && (pIoVrb->MdlAddress)) {
KeFlushIoBuffers(pIoVrb->MdlAddress, FALSE, TRUE);
}
//
// Flush the adapter buffers if necessary.
//
if (pIoVrb->pMapRegisterBase) {
//
// Since we are a master we can call I/O flush adapter buffers with
// a NULL adapter. This is done both before the dma starts and after
// it completes.
//
IoFlushAdapterBuffers(NULL, // AdapterObject.
pIoVrb->MdlAddress, // MdlAddress hidden from Irp.
pIoVrb->pMapRegisterBase, // Map Register base.
pMdlVirt, // Current virtual address.
pIoVrb->InputBufferSize, // Current virtual address size.
TRUE); // TRUE for writes from system memory.
}
//
// If miniport wants so unlock memory, do so here. At this point free the
// map registers and release the DMA_PARAMETERs.
//
if (pVDRB->vrp.bUnlock) {
pVideoDebugPrint((VIDEO_DMA_LOCK, "Unlocking, pIoVrb:%x\n", pIoVrb));
pVideoDebugPrint((VIDEO_DMA_LOCK, "Unlocking, MdlAddress:%x\n", pIoVrb->MdlAddress));
pVideoPortUnlockPages(pDE, pIoVrb);
//
// Free the map registers.
//
IoFreeMapRegisters(pDE->DmaAdapterObject,
pIoVrb->pMapRegisterBase,
pIoVrb->NumberOfMapRegisters);
//
// Clear the MapRegisterBase, unlock the pages and free the Mdls.
//
pIoVrb->pMapRegisterBase = NULL;
//
// The following frees the PDMA_PARAMETERS pIoVrb.
//
pVideoPortReleaseDmaParameters(pVDRB, pIoVrb);
}
return NO_ERROR;
}
PDMA_PARAMETERS
pVideoPortGetIoVrbData(
PDEVICE_EXTENSION deviceExtension,
PVIDEO_DMA_REQUEST_BLOCK pVDRB
)
{
return (deviceExtension->MapDmaParameters);
}
/******************************************************************/
/******************************************************************/
/******************************************************************/
/* FILE: dmapub.c public stuff
*/
#define MAX_COMMON_BUFFER_SIZE 4096
PVOID
VideoPortGetCommonBuffer(
IN PVOID HwDeviceExtension,
IN ULONG Length,
OUT PPHYSICAL_ADDRESS pLogicalAddress,
IN BOOLEAN CacheEnabled
)
/*++
Routine Description:
Provides physical address visible to both device and system. Memory
seen as coniguous by device.
Arguments:
HwDeviceExtension - device extension available to miniport.
Length - size of desired memory (should be minimal).
pLogicalAddress - [out] parameter which will hold PHYSICAL_ADDRESS
upon function return.
CacheEnabled - Specifies whether the allocated memory can be cached.
Return Value:
--*/
{
PDEVICE_EXTENSION deviceExtension =
((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
if (Length > MAX_COMMON_BUFFER_SIZE) {
return NULL;
}
return (HalAllocateCommonBuffer(deviceExtension->DmaAdapterObject,
Length,
pLogicalAddress,
CacheEnabled
));
}
PVOID
VideoPortGetScatterGatherList(
IN PVOID HwDeviceExtension,
IN PVIDEO_REQUEST_PACKET pVrp,
IN PVOID VirtualAddress,
OUT PULONG pListLength
)
/*++
Routine Description:
Returns scatter gather list to miniport for DMA. Caller can use
GET_VIDEO_PHYSICAL_ADDRESS (see video.h) to get the pieces and size of
the contiguous pages.
Arguments:
Return Value:
--*/
{
PDEVICE_EXTENSION deviceExtension =
((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
PVIDEO_DMA_REQUEST_BLOCK pVDRB;
GET_PVRB_FROM_PVRP(pVDRB, pVrp);
if (pVDRB) {
PDMA_PARAMETERS pIoVrb = pVideoPortGetIoVrbData(deviceExtension,
pVDRB);
PVRB_SG pScatterList;
//
// A scatter/gather list has already been allocated.
// Get the scatter/gather list.
//
*pListLength = pIoVrb->NumberOfMapRegisters;
return (pIoVrb->pScatterGather);
}
return NULL;
}
// BUGBUG: currently, this does nothing.
//
VOID
VideoPortNotification(
ULONG VideoStatus,
PVOID pHWDevExt,
...
)
{
PDEVICE_EXTENSION pHWDeviceExtension = (PDEVICE_EXTENSION)pHWDevExt;
va_list ap;
va_start(ap, pHWDevExt);
switch(VideoStatus)
{
default:
pHWDeviceExtension->VRBFlags = 1;
}
va_end(ap);
}
BOOLEAN
VideoPortDoDma(
IN PVOID HwDeviceExtension,
IN PVIDEO_REQUEST_PACKET pVrp,
PVOID pUEvent
)
/*++
Routine Description:
This function is called by the miniport when a display driver calls
IoControl with IOCTL_VIDEO_DMA_TRANSFER or IOCTL_VIDEO_DMA_INIT.
This routine get a
PDMA_PARAMETERS, the context passed into the IO subsystem. It then checks
to see if that PDMA_PARAMETERS refers to a scattergather list. If so, it
jumps to calling the synchronization function which calls back to call
the HwStartDma routine. If no scattergather list is built, this routine
calls the appropriate Mm, Ke and Io routines to allocate MDLs, flush
buffers and map memory. It also computes the number of map registers
required and CURRENTLY FAILS the call if the buffer requested is too
large. If the number of map registers can be satisfied, it then calls
IoAllocateAdapterChannel to set up the dma device. If this succeeds,
it sets the OutputBuffer to contain a pointer to the scattergather list,
the OutputBufferLength to the length of this list and falls through
to the synchronization referred to above. Note that the Irp->MdlAddress
is NOT USED, as this forces the IoSubsystem to free that PMDL when
the Irp completes.
Arguments:
pDE - a pointer to a DEVICE_EXTENSION
pVrp - a pointer to a PVIDEO_REQUEST_PACKET.
pUEvent - a pointer to an USER EVENT object
Return Value:
VOID.
--*/
{
PDEVICE_EXTENSION deviceExtension =
((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
PVIDEO_DMA_REQUEST_BLOCK pVDRB;
PDMA_PARAMETERS pIoVrb;
KIRQL currentIrql;
PMDL pMdl;
GET_PVRB_FROM_PVRP(pVDRB, pVrp);
pIoVrb = pVideoPortGetDmaParameters(deviceExtension, pVDRB);
//
// Asynchronous mode could start here.
//
if (!pIoVrb) {
//
// Can't get DmaParameter storage. set flag and return
//
deviceExtension->VRBFlags |= INSUFFICIENT_DMA_RESOURCES;
pVideoDebugPrint((0, "Can't get DMA parameter storage\n"));
return FALSE;
}
if (pIoVrb->pScatterGather &&
(deviceExtension->AdapterInterfaceType != Isa) ) {
pVideoDebugPrint((0, "Skip list building\n"));
goto LIST_BUILT;
}
//
// If the miniport passed in a User mode event object, map it
// to a KEVENT, and stick that into the pIoVrb.
//
if (pUEvent) {
PKEVENT pTmpKEvent = &pIoVrb->MappedUserEvent;
NTSTATUS status;
KPROCESSOR_MODE PreviousMode;
LONG State;
//
// Make sure the pUEvent ain't bogus: steal the event code
// from ntos\ex\event.c
//
try {
status = ObReferenceObjectByHandle((HANDLE)pUEvent,
GENERIC_ALL,
NULL,
KernelMode,
&pTmpKEvent,
NULL);
//
// If the reference was successful, then pulse the event object,
// dereference event object, and write the previous state value if
// specified. If the write of the previous state fails, then do not
// report an error. When the caller attempts to access the previous
// state value, an access violation will occur.
//
if (NT_SUCCESS(status)) {
State = KePulseEvent(pTmpKEvent, EVENT_INCREMENT, FALSE);
ObDereferenceObject(pTmpKEvent);
}
//
// If an exception occurs during the probe of the previous state, then
// always handle the exception, get the exception code and return FALSE.
//
} except(ExSystemExceptionFilter()) {
GetExceptionCode();
return FALSE;
}
}
deviceExtension->MapDmaParameters = pIoVrb;
//
// Init IoAllocAdapterChannel event in NOT SIGNALLED state.
//
KeInitializeEvent(&(pIoVrb->IoAllocEvent),
NotificationEvent,
FALSE);
//
// Get Mdl for user buffer.
//
pVideoDebugPrint((VIDEO_DMA_DO_MDL,
"InputBuffer:%x, length:%d\n",
pVDRB->vrp.InputBuffer, pVDRB->vrp.InputBufferLength));
//
// Allocate the MDL, but don't stuff it in the Irp, as IoCompleteRequest
// will free it.
//
pIoVrb->MdlAddress = IoAllocateMdl(pVDRB->vrp.InputBuffer,
pVDRB->vrp.InputBufferLength,
FALSE,
FALSE,
NULL);
if (!pIoVrb->MdlAddress) {
VideoPortDebugPrint(VIDEO_DMA_DO_MDL,
"VideoPortIoStartRequest: Can't allocate Mdl\n");
pVDRB->vrp.StatusBlock->Status = VRB_STATUS_INVALID_REQUEST;
VideoPortNotification(RequestComplete,
deviceExtension,
pIoVrb);
VideoPortNotification(NextRequest,
deviceExtension);
//
// Queue a DPC to process the work that was just indicated.
//
IoRequestDpc(deviceExtension->DeviceObject, NULL, NULL);
pVideoDebugPrint((0,
"************* Queued a DPC, no MDL address *************\n"));
return FALSE;
}
//
// Save the Mdl virtual address
//
pVideoDebugPrint((VIDEO_DMA_DO_MDL,
"Saved MdlAddr %x off of DMA_PARAM:%x\n",
pIoVrb->MdlAddress, pIoVrb));
pIoVrb->DataOffset = MmGetMdlVirtualAddress((PMDL)pIoVrb->MdlAddress);
//
// Save the size of the input buffer in the DMA_PARAMETERS
//
pIoVrb->InputBufferSize = pVDRB->vrp.InputBufferLength;
//
// Determine if the device needs mapped memory.
//
if (deviceExtension->bMapBuffers) {
if (pIoVrb->MdlAddress) {
pIoVrb->DataOffset = MmGetSystemAddressForMdl((PMDL)pIoVrb->MdlAddress);
pVDRB->vrp.InputBuffer = ((PUCHAR)pIoVrb->DataOffset) +
(ULONG)(((PUCHAR)pVDRB->vrp.InputBuffer) - ((PUCHAR)MmGetMdlVirtualAddress((PMDL)pIoVrb->MdlAddress)));
pVideoDebugPrint((VIDEO_DMA_DO_MDL, "Mapped Buffers\n"));
}
}
if (deviceExtension->DmaAdapterObject) {
//
// If the buffer is not mapped then the I/O buffer must be flushed
// to aid in cache coherency.
//
KeFlushIoBuffers(pIoVrb->MdlAddress, FALSE, TRUE);
pVideoDebugPrint((VIDEO_DMA_DO_MDL, "Flushed Buffers\n"));
}
//
// Determine if this adapter needs map registers
//
if (deviceExtension->bMasterWithAdapter) {
//
// Calculate the number of map registers needed for this transfer.
// Note that this may be recalculated if the miniport really wants
// to do DMA
//
pVideoDebugPrint((VIDEO_DMA_DO, "bufferlength:%d\n", pVDRB->vrp.InputBufferLength));
pIoVrb->NumberOfMapRegisters = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
pVDRB->vrp.InputBuffer,
pVDRB->vrp.InputBufferLength
);
}
pVideoDebugPrint((VIDEO_DMA_DO,
"#map registers:%d\n",
pIoVrb->NumberOfMapRegisters));
pVideoDebugPrint((VIDEO_DMA_DO,
"Max Phy Pages %d:\n",
deviceExtension->Capabilities.MaximumPhysicalPages));
while (pIoVrb->NumberOfMapRegisters >
deviceExtension->Capabilities.MaximumPhysicalPages) {
pVideoDebugPrint((0, "Too few map registers\n"));
pVideoPortReleaseDmaParameters(pVDRB, pIoVrb);
return FALSE;
#if 0
//
// The miniport may have requested too big of a buffer, so iteratively
// chop it in half until we find one we can do. This changes the
// vrp.InputBufferLength, which the miniport must check to see how much
// is actually sent and queue up the remainder.
//
pVideoDebugPrint((VIDEO_DMA_DO, "Halving inputbuffers!!!\n"));
pVDRB->vrp.InputBufferLength /= 2;
pIoVrb->NumberOfMapRegisters = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
pVDRB->vrp.InputBuffer,
pVDRB->vrp.InputBufferLength
);
#endif
}
ASSERT(pIoVrb->NumberOfMapRegisters);
//
// Lock the users buffer down.
//
pMdl = pIoVrb->MdlAddress;
__try {
pVideoDebugPrint((VIDEO_DMA_LOCK, "Locking pIoVrb:%x\n", pIoVrb));
pVideoDebugPrint((VIDEO_DMA_LOCK, "Locking mdl:%x\n", pMdl));
VideoPortDebugPrint(VIDEO_DMA_LOCK,
"BuildSG, about to probe and lock mdl %x hanging off PDMA %x\n",
pMdl, pIoVrb);
MmProbeAndLockPages(pMdl,
KernelMode,
IoModifyAccess);
} __except(EXCEPTION_EXECUTE_HANDLER) {
IoFreeMdl(pIoVrb->MdlAddress);
VideoPortDebugPrint(0,
"VideoPortIoStartRequest: MmProbeandLockPages exception\n");
}
VideoPortDebugPrint(VIDEO_DMA_LOCK, "BuildSG, locked pages\n");
//
// Allocate the adapter channel with sufficient map registers
// for the transfer. Be sure to be at DISPATCH_LEVEL IRQL.
//
pVideoDebugPrint((VIDEO_DMA_DO,
"Calling IoAllocateAdapterChannel with %d map registers\n",
pIoVrb->NumberOfMapRegisters));
KeResetEvent(&(pIoVrb->IoAllocEvent));
KeRaiseIrql(DISPATCH_LEVEL, &currentIrql );
IoAllocateAdapterChannel(
deviceExtension->DmaAdapterObject, // AdapterObject
deviceExtension->DeviceObject, // DeviceObject
pIoVrb->NumberOfMapRegisters, // NumberOfMapRegisters
pVideoPortBuildScatterGather, // ExecutionRoutine (Must return DeallocateObjectKeepRegisters)
pIoVrb); // Context
KeLowerIrql(currentIrql);
pVideoDebugPrint((VIDEO_DMA_DO, "Returned from IoAllocateAdapterChannel\n"));
//
// Wait until there's a scatter gather list built.
//
KeWaitForSingleObject(&(pIoVrb->IoAllocEvent),
Executive,
KernelMode,
FALSE,
(PTIME)NULL);
//
// Put DMA context into OutputBuffer.
//
*(PULONG)(pVrp->OutputBuffer) = (ULONG)pIoVrb;
LIST_BUILT:
pIoVrb->pDE = deviceExtension;
KeAcquireSpinLock(&deviceExtension->SpinLock, &currentIrql);
deviceExtension->SynchronizeExecution(
deviceExtension->InterruptObject,
pVideoPortStartDmaSynchronized,
pIoVrb
);
KeReleaseSpinLock(&deviceExtension->SpinLock, currentIrql);
return TRUE;
}
#if 0
DEAD CODE
BOOLEAN
pVideoGetInterruptState(
IN PVOID ServiceContext
)
/*++
Routine Description:
This routine saves the InterruptFlags, MapTransferParameters and
CompletedRequests fields and clears the InterruptFlags.
This routine also removes the request from the logical unit queue if it is
tag. Finally the request time is updated.
Arguments:
ServiceContext - Supplies a pointer to the interrupt context which contains
pointers to the interrupt data and where to save it.
Return Value:
Returns TRUE if there is new work and FALSE otherwise.
Notes:
Called via KeSynchronizeExecution with the port device extension spinlock
held.
--*/
{
PINTERRUPT_CONTEXT interruptContext = ServiceContext;
ULONG limit = 0;
PDEVICE_EXTENSION deviceExtension;
PVIDEO_DMA_REQUEST_BLOCK pVDRB;
PDMA_PARAMETERS pIoVrb;
deviceExtension = interruptContext->pDE;
//
// Check for pending work.
//
if (!(deviceExtension->InterruptFlags & NOTIFY_REQUIRED)) {
return(FALSE);
}
//
// Move the interrupt state to save area.
//
interruptContext->InterruptFlags =
deviceExtension->pInterruptContext->InterruptFlags;
//
// Clear the interrupt state.
//
deviceExtension->InterruptFlags &= INTERRUPT_FLAG_MASK;
pIoVrb = interruptContext->pDmaParameters;
if (pIoVrb != NULL) {
//
// Get a pointer to the DMA_PARAMETERS.
//
pVDRB = pIoVrb->pVideoRequestBlock;
ASSERT(pVDRB != NULL);
//
// If the request did not succeed, then check for the special cases.
//
if (pVDRB->vrp.StatusBlock->Status != VRB_STATUS_SUCCESS) {
//
// Check for a QUEUE FULL status.
//
if (pVDRB->vrp.StatusBlock->Status & VRB_QUEUE_FULL) {
//
// Set the queue full flag in the logical unit to prevent
// any new requests from being started.
//
pVDRB->VRBFlags |= QUEUE_IS_FULL;
}
}
}
return(TRUE);
}
DEADCODE
#endif