2388 lines
48 KiB
C
2388 lines
48 KiB
C
/*++
|
||
|
||
Copyright (c) 1990-2000 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
ops.c
|
||
|
||
Abstract:
|
||
|
||
video port stub routines for memory and io.
|
||
|
||
Author:
|
||
|
||
Andre Vachon (andreva) 22-Feb-1997
|
||
|
||
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 "videoprt.h"
|
||
|
||
#pragma alloc_text(PAGE,VideoPortGetAssociatedDeviceExtension)
|
||
#pragma alloc_text(PAGE,VideoPortGetAssociatedDeviceID)
|
||
#pragma alloc_text(PAGE,VideoPortAcquireDeviceLock)
|
||
#pragma alloc_text(PAGE,VideoPortReleaseDeviceLock)
|
||
#pragma alloc_text(PAGE,VideoPortGetRomImage)
|
||
#pragma alloc_text(PAGE,VpGetBusInterface)
|
||
#pragma alloc_text(PAGE,VideoPortGetVgaStatus)
|
||
#pragma alloc_text(PAGE,pVideoPortGetVgaStatusPci)
|
||
#pragma alloc_text(PAGE,VideoPortCheckForDeviceExistence)
|
||
#pragma alloc_text(PAGE,VpGetDeviceCount)
|
||
#pragma alloc_text(PAGE,VideoPortRegisterBugcheckCallback)
|
||
#pragma alloc_text(PAGE,VpAllocateNonPagedPoolPageAligned)
|
||
#pragma alloc_text(PAGE,VpAcquireLock)
|
||
#pragma alloc_text(PAGE,VpReleaseLock)
|
||
|
||
//
|
||
//ULONG
|
||
//VideoPortCompareMemory (
|
||
// PVOID Source1,
|
||
// PVOID Source2,
|
||
// ULONG Length
|
||
// )
|
||
//Forwarded to RtlCompareMemory(Source1,Source2,Length);
|
||
//
|
||
|
||
|
||
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.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
|
||
|
||
//
|
||
// Only perform this operation if the interurpt is actually connected.
|
||
//
|
||
|
||
if (fdoExtension->InterruptObject) {
|
||
|
||
HalDisableSystemInterrupt(fdoExtension->InterruptVector,
|
||
fdoExtension->InterruptIrql);
|
||
|
||
fdoExtension->InterruptsEnabled = FALSE;
|
||
|
||
return NO_ERROR;
|
||
|
||
} else {
|
||
|
||
return ERROR_INVALID_FUNCTION;
|
||
|
||
}
|
||
|
||
} // VideoPortDisableInterrupt()
|
||
|
||
|
||
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.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
|
||
|
||
//
|
||
// Only perform this operation if the interurpt is actually connected.
|
||
//
|
||
|
||
if (fdoExtension->InterruptObject) {
|
||
|
||
fdoExtension->InterruptsEnabled = TRUE;
|
||
|
||
HalEnableSystemInterrupt(fdoExtension->InterruptVector,
|
||
fdoExtension->InterruptIrql,
|
||
fdoExtension->InterruptMode);
|
||
|
||
return NO_ERROR;
|
||
|
||
} else {
|
||
|
||
return ERROR_INVALID_FUNCTION;
|
||
|
||
}
|
||
|
||
} // VideoPortEnableInterrupt()
|
||
|
||
PVOID
|
||
VideoPortGetRomImage(
|
||
IN PVOID HwDeviceExtension,
|
||
IN PVOID Unused1,
|
||
IN ULONG Unused2,
|
||
IN ULONG Length
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine allows a miniport driver to get a copy of its devices
|
||
ROM. This function returns the pointer to a buffer containing the
|
||
devices ROM.
|
||
|
||
Arguments;
|
||
|
||
HwDeviceExtension - Points to the miniport driver's device extension.
|
||
|
||
Unused1 - Reserved for future use. Must be NULL. (Buffer)
|
||
|
||
Unused2 - Reserved for future use. Must be zero. (Offset)
|
||
|
||
Length - Number of bytes to return.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
|
||
|
||
#if DBG
|
||
if ((Unused1 != NULL) || (Unused2 != 0)) {
|
||
pVideoDebugPrint((0,"VideoPortGetRomImage - Unused1 and Unused2 must be zero\n"));
|
||
ASSERT(FALSE);
|
||
return NULL;
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// Each time this routine is called the previous contents of the ROM
|
||
// image are dropped.
|
||
//
|
||
|
||
if (fdoExtension->RomImage) {
|
||
ExFreePool(fdoExtension->RomImage);
|
||
fdoExtension->RomImage = NULL;
|
||
}
|
||
|
||
//
|
||
// The caller should try to grab a buffer of length zero to free
|
||
// any ROM Image already returned.
|
||
//
|
||
|
||
if (Length == 0) {
|
||
return NULL;
|
||
}
|
||
|
||
//
|
||
// This entry point is only valid for PnP Drivers.
|
||
//
|
||
|
||
if (((fdoExtension->Flags & LEGACY_DRIVER) == 0) &&
|
||
fdoExtension->ValidBusInterface) {
|
||
|
||
NTSTATUS status;
|
||
PUCHAR Buffer;
|
||
ULONG len, len1;
|
||
PUCHAR outputBuffer;
|
||
|
||
//
|
||
// Allocate memory for our buffer
|
||
//
|
||
|
||
Buffer = ExAllocatePoolWithTag(PagedPool,
|
||
Length * sizeof(UCHAR),
|
||
VP_TAG);
|
||
|
||
if (!Buffer) {
|
||
|
||
pVideoDebugPrint((1, "VideoPortGetRomImage - could not allocate buffer\n"));
|
||
return NULL;
|
||
}
|
||
|
||
// Try ACPI _ROM method first
|
||
outputBuffer = ExAllocatePoolWithTag(PagedPool,
|
||
(0x1000 + sizeof(ACPI_EVAL_OUTPUT_BUFFER))*sizeof(UCHAR),
|
||
VP_TAG);
|
||
if (!outputBuffer) {
|
||
ExFreePool(Buffer);
|
||
pVideoDebugPrint((1, "VideoPortGetRomImage - could not allocate buffer\n"));
|
||
return NULL;
|
||
}
|
||
|
||
for (len = 0; len < Length; len += len1)
|
||
{
|
||
// _ROM can transfer only 4K at one time
|
||
len1 = ((Length-len) < 0x1000) ? (Length-len) : 0x1000;
|
||
status = pVideoPortACPIIoctl(
|
||
fdoExtension->AttachedDeviceObject,
|
||
(ULONG) ('MOR_'),
|
||
&len,
|
||
&len1,
|
||
len1+sizeof(ACPI_EVAL_OUTPUT_BUFFER),
|
||
(PACPI_EVAL_OUTPUT_BUFFER) outputBuffer);
|
||
if (!NT_SUCCESS(status))
|
||
break;
|
||
RtlCopyMemory(Buffer+len,
|
||
((PACPI_EVAL_OUTPUT_BUFFER)outputBuffer)->Argument[0].Data,
|
||
len1 * sizeof(UCHAR));
|
||
}
|
||
|
||
ExFreePool(outputBuffer);
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
fdoExtension->RomImage = Buffer;
|
||
return Buffer;
|
||
}
|
||
|
||
// If ACPI _ROM method failed
|
||
Length = fdoExtension->BusInterface.GetBusData(
|
||
fdoExtension->BusInterface.Context,
|
||
PCI_WHICHSPACE_ROM,
|
||
Buffer,
|
||
0,
|
||
Length);
|
||
|
||
if (Length) {
|
||
|
||
fdoExtension->RomImage = Buffer;
|
||
return Buffer;
|
||
|
||
} else {
|
||
|
||
ExFreePool(Buffer);
|
||
return NULL;
|
||
}
|
||
|
||
} else {
|
||
|
||
pVideoDebugPrint((0, "VideoPortGetRomImage - not supported on legacy devices\n"));
|
||
return NULL;
|
||
}
|
||
}
|
||
|
||
|
||
ULONG
|
||
VideoPortGetBusData(
|
||
PVOID HwDeviceExtension,
|
||
IN BUS_DATA_TYPE BusDataType,
|
||
IN ULONG SlotNumber,
|
||
IN PVOID Buffer,
|
||
IN ULONG Offset,
|
||
IN ULONG Length
|
||
)
|
||
|
||
{
|
||
PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
|
||
|
||
if ((fdoExtension->Flags & LEGACY_DRIVER) ||
|
||
(BusDataType != PCIConfiguration)) {
|
||
|
||
#if defined(NO_LEGACY_DRIVERS)
|
||
pVideoDebugPrint((0, "VideoPortGetBusData: fdoExtension->Flags & LEGACY_DRIVER not supported for 64-bits.\n"));
|
||
|
||
return 0;
|
||
|
||
#else
|
||
return HalGetBusDataByOffset(BusDataType,
|
||
fdoExtension->SystemIoBusNumber,
|
||
SlotNumber,
|
||
Buffer,
|
||
Offset,
|
||
Length);
|
||
#endif // NO_LEGACY_DRIVERS
|
||
|
||
} else {
|
||
|
||
if (fdoExtension->ValidBusInterface) {
|
||
Length = fdoExtension->BusInterface.GetBusData(
|
||
fdoExtension->BusInterface.Context,
|
||
PCI_WHICHSPACE_CONFIG,
|
||
Buffer,
|
||
Offset,
|
||
Length);
|
||
|
||
return Length;
|
||
} else {
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
} // end VideoPortGetBusData()
|
||
|
||
|
||
UCHAR
|
||
VideoPortGetCurrentIrql(
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Stub to get Current Irql.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
return (KeGetCurrentIrql());
|
||
|
||
} // VideoPortGetCurrentIrql()
|
||
|
||
|
||
ULONG
|
||
VideoPortSetBusData(
|
||
PVOID HwDeviceExtension,
|
||
IN BUS_DATA_TYPE BusDataType,
|
||
IN ULONG SlotNumber,
|
||
IN PVOID Buffer,
|
||
IN ULONG Offset,
|
||
IN ULONG Length
|
||
)
|
||
|
||
{
|
||
|
||
PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
|
||
|
||
if ((fdoExtension->Flags & LEGACY_DRIVER) ||
|
||
(BusDataType != PCIConfiguration)) {
|
||
|
||
#if defined(NO_LEGACY_DRIVERS)
|
||
pVideoDebugPrint((0, "VideoPortSetBusData: fdoExtension->Flags & LEGACY_DRIVER not supported for 64-bits.\n"));
|
||
|
||
return 0;
|
||
|
||
#else
|
||
|
||
return HalSetBusDataByOffset(BusDataType,
|
||
fdoExtension->SystemIoBusNumber,
|
||
SlotNumber,
|
||
Buffer,
|
||
Offset,
|
||
Length);
|
||
#endif // NO_LEGACY_DRIVERS
|
||
|
||
} else {
|
||
|
||
if (fdoExtension->ValidBusInterface) {
|
||
Length = fdoExtension->BusInterface.SetBusData(
|
||
fdoExtension->BusInterface.Context,
|
||
PCI_WHICHSPACE_CONFIG,
|
||
Buffer,
|
||
Offset,
|
||
Length);
|
||
|
||
return Length;
|
||
} else {
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
} // end VideoPortSetBusData()
|
||
|
||
|
||
//
|
||
//VOID
|
||
//VideoPortStallExecution(
|
||
// IN ULONG Microseconds
|
||
// )
|
||
//
|
||
//Forwarded to KeStallExecutionProcessor(Microseconds);
|
||
//
|
||
|
||
|
||
//
|
||
//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 to the appropriate kernel function.
|
||
// This saves time and memory
|
||
//
|
||
|
||
#if DBG || !defined(_X86_)
|
||
|
||
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;
|
||
|
||
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;
|
||
|
||
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;
|
||
|
||
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));
|
||
|
||
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));
|
||
|
||
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));
|
||
|
||
READ_PORT_BUFFER_ULONG(Port, Buffer, Count);
|
||
|
||
} // VideoPortReadPortBufferUlong()
|
||
|
||
#endif
|
||
|
||
|
||
//
|
||
// ALL the functions to read ports and registers are forwarded on free
|
||
// builds on x86 to the appropriate kernel function.
|
||
// This saves time and memory
|
||
//
|
||
|
||
#if DBG || !defined(_X86_)
|
||
|
||
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;
|
||
|
||
temp = READ_REGISTER_UCHAR(Register);
|
||
|
||
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;
|
||
|
||
temp = READ_REGISTER_USHORT(Register);
|
||
|
||
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;
|
||
|
||
temp = READ_REGISTER_ULONG(Register);
|
||
|
||
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
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
READ_REGISTER_BUFFER_UCHAR(Register, Buffer, Count);
|
||
}
|
||
|
||
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
|
||
|
||
--*/
|
||
|
||
{
|
||
READ_REGISTER_BUFFER_USHORT(Register, Buffer, Count);
|
||
}
|
||
|
||
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
|
||
|
||
--*/
|
||
|
||
{
|
||
READ_REGISTER_BUFFER_ULONG(Register, Buffer, Count);
|
||
}
|
||
|
||
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));
|
||
|
||
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));
|
||
|
||
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));
|
||
|
||
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));
|
||
|
||
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));
|
||
|
||
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));
|
||
|
||
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));
|
||
|
||
WRITE_REGISTER_UCHAR(Register, Value);
|
||
|
||
} // 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));
|
||
|
||
WRITE_REGISTER_USHORT(Register, Value);
|
||
|
||
} // 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));
|
||
|
||
WRITE_REGISTER_ULONG(Register, Value);
|
||
|
||
} // 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
|
||
|
||
--*/
|
||
|
||
{
|
||
WRITE_REGISTER_BUFFER_UCHAR(Register, Buffer, Count);
|
||
}
|
||
|
||
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
|
||
|
||
--*/
|
||
|
||
{
|
||
WRITE_REGISTER_BUFFER_USHORT(Register, Buffer, Count);
|
||
}
|
||
|
||
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
|
||
|
||
--*/
|
||
|
||
{
|
||
WRITE_REGISTER_BUFFER_ULONG(Register, Buffer, Count);
|
||
}
|
||
|
||
#endif // DBG
|
||
|
||
//
|
||
//VOID
|
||
//VideoPortZeroMemory(
|
||
// IN PVOID Destination,
|
||
// IN ULONG Length
|
||
// )
|
||
//
|
||
//Forwarded to RtlZeroMemory(Destination,Length);
|
||
//
|
||
|
||
PVOID
|
||
VideoPortGetAssociatedDeviceExtension(
|
||
IN PVOID DeviceObject
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will return the HwDeviceExtension for the parent of the
|
||
given device object.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - The child device object (PDO).
|
||
|
||
Notes:
|
||
|
||
This function is useful if you want to get the parent device extension
|
||
for a child device object. For example this is useful with I2C.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFDO_EXTENSION DeviceExtension;
|
||
PCHILD_PDO_EXTENSION ChildDeviceExtension;
|
||
|
||
PAGED_CODE();
|
||
ASSERT(NULL != DeviceObject);
|
||
|
||
ChildDeviceExtension = (PCHILD_PDO_EXTENSION)((PDEVICE_OBJECT)DeviceObject)->DeviceExtension;
|
||
|
||
if (!IS_PDO(ChildDeviceExtension)) {
|
||
ASSERT(FALSE);
|
||
return NULL;
|
||
}
|
||
|
||
DeviceExtension = (PFDO_EXTENSION)ChildDeviceExtension->pFdoExtension;
|
||
return (PVOID) DeviceExtension->HwDeviceExtension;
|
||
}
|
||
|
||
ULONG
|
||
VideoPortGetAssociatedDeviceID(
|
||
IN PVOID DeviceObject
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will return the ChildId for the given device object.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - The child device object (PDO).
|
||
|
||
Notes:
|
||
|
||
This function is useful if you want to get the child ID
|
||
for a child device object. For example this is useful with I2C.
|
||
|
||
--*/
|
||
|
||
{
|
||
PCHILD_PDO_EXTENSION ChildDeviceExtension;
|
||
|
||
PAGED_CODE();
|
||
ASSERT(NULL != DeviceObject);
|
||
|
||
ChildDeviceExtension = (PCHILD_PDO_EXTENSION)((PDEVICE_OBJECT)DeviceObject)->DeviceExtension;
|
||
|
||
if (!IS_PDO(ChildDeviceExtension)) {
|
||
ASSERT(FALSE);
|
||
return VIDEO_INVALID_CHILD_ID;
|
||
}
|
||
|
||
return ChildDeviceExtension->ChildUId;
|
||
}
|
||
|
||
VOID
|
||
VideoPortAcquireDeviceLock(
|
||
IN PVOID HwDeviceExtension
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine acquires the per device lock maintained by the videoprt.
|
||
|
||
Arguments:
|
||
|
||
HwDeviceExtension - Pointer to the hardware device extension.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
|
||
|
||
ACQUIRE_DEVICE_LOCK(fdoExtension);
|
||
}
|
||
|
||
VOID
|
||
VideoPortReleaseDeviceLock(
|
||
IN PVOID HwDeviceExtension
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine releases the per device lock maintained by the videoprt.
|
||
|
||
Arguments:
|
||
|
||
HwDeviceExtension - Pointer to the hardware device extension.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
|
||
|
||
RELEASE_DEVICE_LOCK(fdoExtension);
|
||
}
|
||
|
||
PVOID
|
||
VpGetProcAddress(
|
||
IN PVOID HwDeviceExtension,
|
||
IN PUCHAR FunctionName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine allows a video miniport to get access to VideoPort
|
||
functions without linking to them directly. This will allow an NT 5.0
|
||
miniport to take advantage of NT 5.0 features while running on NT 5.0,
|
||
but still retain the ability to load on NT 4.0.
|
||
|
||
Arguments:
|
||
|
||
HwDeviceExtension - Pointer to the hardware device extension.
|
||
|
||
FunctionName - pointer to a zero terminated ascii string which contains
|
||
the function name we are looking for.
|
||
|
||
Returns:
|
||
|
||
Pointer to the given function if it exists.
|
||
NULL otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
|
||
PPROC_ADDRESS ProcAddress = VideoPortEntryPoints;
|
||
|
||
//
|
||
// Since the list of exported functions is small, and this routine
|
||
// will not be called often we can get away with a linear search.
|
||
//
|
||
|
||
while (ProcAddress->FunctionName) {
|
||
|
||
if (strcmp(ProcAddress->FunctionName, FunctionName) == 0) {
|
||
return ProcAddress->FunctionAddress;
|
||
}
|
||
|
||
ProcAddress++;
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
NTSTATUS
|
||
VpGetBusInterface(
|
||
PFDO_EXTENSION FdoExtension
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Send a QueryInterface Irp to our parent to retrieve
|
||
the BUS_INTERFACE_STANDARD.
|
||
|
||
Returns:
|
||
|
||
NT_STATUS code
|
||
|
||
--*/
|
||
|
||
{
|
||
KEVENT Event;
|
||
PIRP QueryIrp = NULL;
|
||
IO_STATUS_BLOCK IoStatusBlock;
|
||
PIO_STACK_LOCATION NextStack;
|
||
NTSTATUS Status;
|
||
|
||
KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
|
||
|
||
QueryIrp = IoBuildSynchronousFsdRequest(IRP_MJ_FLUSH_BUFFERS,
|
||
FdoExtension->AttachedDeviceObject,
|
||
NULL,
|
||
0,
|
||
NULL,
|
||
&Event,
|
||
&IoStatusBlock);
|
||
|
||
if (QueryIrp == NULL) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
QueryIrp->IoStatus.Status = IoStatusBlock.Status = STATUS_NOT_SUPPORTED;
|
||
|
||
NextStack = IoGetNextIrpStackLocation(QueryIrp);
|
||
|
||
//
|
||
// Set up for a QueryInterface Irp.
|
||
//
|
||
|
||
NextStack->MajorFunction = IRP_MJ_PNP;
|
||
NextStack->MinorFunction = IRP_MN_QUERY_INTERFACE;
|
||
|
||
NextStack->Parameters.QueryInterface.InterfaceType = &GUID_BUS_INTERFACE_STANDARD;
|
||
NextStack->Parameters.QueryInterface.Size = sizeof(BUS_INTERFACE_STANDARD);
|
||
NextStack->Parameters.QueryInterface.Version = 1;
|
||
NextStack->Parameters.QueryInterface.Interface = (PINTERFACE) &FdoExtension->BusInterface;
|
||
NextStack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
|
||
|
||
FdoExtension->BusInterface.Size = sizeof(BUS_INTERFACE_STANDARD);
|
||
FdoExtension->BusInterface.Version = 1;
|
||
|
||
Status = IoCallDriver(FdoExtension->AttachedDeviceObject, QueryIrp);
|
||
|
||
if (Status == STATUS_PENDING) {
|
||
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
||
Status = IoStatusBlock.Status;
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
BOOLEAN
|
||
VideoPortCheckForDeviceExistence(
|
||
IN PVOID HwDeviceExtension,
|
||
IN USHORT VendorId,
|
||
IN USHORT DeviceId,
|
||
IN UCHAR RevisionId,
|
||
IN USHORT SubVendorId,
|
||
IN USHORT SubSystemId,
|
||
IN ULONG Flags
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Checks for the existance of a given PCI device in the system.
|
||
|
||
Returns:
|
||
|
||
TRUE if the device is present,
|
||
FALSE otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFDO_EXTENSION FdoExtension = GET_FDO_EXT(HwDeviceExtension);
|
||
BOOLEAN Result = FALSE;
|
||
|
||
if ((FdoExtension->Flags & LEGACY_DRIVER) == 0) {
|
||
|
||
KEVENT Event;
|
||
PIRP QueryIrp = NULL;
|
||
IO_STATUS_BLOCK IoStatusBlock;
|
||
PIO_STACK_LOCATION NextStack;
|
||
NTSTATUS Status;
|
||
|
||
PCI_DEVICE_PRESENT_INTERFACE Interface;
|
||
|
||
KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
|
||
|
||
QueryIrp = IoBuildSynchronousFsdRequest(IRP_MJ_FLUSH_BUFFERS,
|
||
FdoExtension->AttachedDeviceObject,
|
||
NULL,
|
||
0,
|
||
NULL,
|
||
&Event,
|
||
&IoStatusBlock);
|
||
|
||
if (QueryIrp == NULL) {
|
||
return FALSE;
|
||
}
|
||
|
||
QueryIrp->IoStatus.Status = IoStatusBlock.Status = STATUS_NOT_SUPPORTED;
|
||
|
||
NextStack = IoGetNextIrpStackLocation(QueryIrp);
|
||
|
||
//
|
||
// Set up for a QueryInterface Irp.
|
||
//
|
||
|
||
NextStack->MajorFunction = IRP_MJ_PNP;
|
||
NextStack->MinorFunction = IRP_MN_QUERY_INTERFACE;
|
||
|
||
NextStack->Parameters.QueryInterface.InterfaceType = &GUID_PCI_DEVICE_PRESENT_INTERFACE;
|
||
NextStack->Parameters.QueryInterface.Size = sizeof(PCI_DEVICE_PRESENT_INTERFACE);
|
||
NextStack->Parameters.QueryInterface.Version = 1;
|
||
NextStack->Parameters.QueryInterface.Interface = (PINTERFACE) &Interface;
|
||
NextStack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
|
||
|
||
FdoExtension->BusInterface.Size = sizeof(PCI_DEVICE_PRESENT_INTERFACE);
|
||
FdoExtension->BusInterface.Version = 1;
|
||
|
||
Status = IoCallDriver(FdoExtension->AttachedDeviceObject, QueryIrp);
|
||
|
||
if (Status == STATUS_PENDING) {
|
||
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
|
||
Status = IoStatusBlock.Status;
|
||
}
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
|
||
//
|
||
// We were able to acquire the interface. Check for our device.
|
||
//
|
||
|
||
Interface.InterfaceReference(Interface.Context);
|
||
|
||
Result = Interface.IsDevicePresent(VendorId,
|
||
DeviceId,
|
||
RevisionId,
|
||
SubVendorId,
|
||
SubSystemId,
|
||
Flags);
|
||
|
||
Interface.InterfaceDereference(Interface.Context);
|
||
|
||
}
|
||
}
|
||
|
||
return Result;
|
||
}
|
||
|
||
//
|
||
// Use these until I can make forwarders work.
|
||
//
|
||
|
||
LONG
|
||
FASTCALL
|
||
VideoPortInterlockedExchange(
|
||
IN OUT PLONG Target,
|
||
IN LONG Value
|
||
)
|
||
|
||
{
|
||
return InterlockedExchange(Target, Value);
|
||
}
|
||
|
||
LONG
|
||
FASTCALL
|
||
VideoPortInterlockedIncrement(
|
||
IN PLONG Addend
|
||
)
|
||
|
||
{
|
||
return InterlockedIncrement(Addend);
|
||
}
|
||
|
||
LONG
|
||
FASTCALL
|
||
VideoPortInterlockedDecrement(
|
||
IN PLONG Addend
|
||
)
|
||
|
||
{
|
||
return InterlockedDecrement(Addend);
|
||
}
|
||
|
||
VP_STATUS
|
||
VideoPortGetVgaStatus(
|
||
PVOID HwDeviceExtension,
|
||
OUT PULONG VgaStatus
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
VideoPortGetVgaStatus detect if the calling device is decoding
|
||
Vga IO address
|
||
|
||
Arguments:
|
||
|
||
HwDeviceExtension - Points to the miniport driver's device extension
|
||
VgaStatus - Points to the the result
|
||
|
||
Return Value:
|
||
|
||
NO_ERROR if the function completes successfully.
|
||
|
||
ERROR_INVALID_FUNCTION if it is a non-PCI device
|
||
|
||
--*/
|
||
{
|
||
|
||
PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
|
||
|
||
//
|
||
// We can not handle legacy devices
|
||
//
|
||
|
||
if (fdoExtension->AdapterInterfaceType != PCIBus) {
|
||
|
||
*VgaStatus = 0;
|
||
|
||
return ERROR_INVALID_FUNCTION;
|
||
}
|
||
else {
|
||
|
||
*VgaStatus = pVideoPortGetVgaStatusPci( HwDeviceExtension );
|
||
return (NO_ERROR);
|
||
|
||
}
|
||
}
|
||
|
||
#define VGA_STATUS_REGISTER1 0x3DA
|
||
|
||
ULONG
|
||
pVideoPortGetVgaStatusPci(
|
||
PVOID HwDeviceExtension
|
||
)
|
||
|
||
{
|
||
|
||
USHORT Command;
|
||
PCI_COMMON_CONFIG ConfigSpace;
|
||
PHYSICAL_ADDRESS PhysicalAddress;
|
||
PUCHAR BaseReg;
|
||
ULONG VgaEnable;
|
||
|
||
//
|
||
// assume VGA is disabled
|
||
//
|
||
|
||
VgaEnable = 0;
|
||
|
||
//
|
||
// Get the PCI config for this device
|
||
//
|
||
|
||
VideoPortGetBusData( HwDeviceExtension,
|
||
PCIConfiguration,
|
||
0,
|
||
&ConfigSpace,
|
||
0,
|
||
PCI_COMMON_HDR_LENGTH);
|
||
|
||
|
||
if( !(ConfigSpace.Command & PCI_ENABLE_IO_SPACE) ) {
|
||
|
||
return VgaEnable;
|
||
|
||
}
|
||
|
||
if (((ConfigSpace.BaseClass == PCI_CLASS_PRE_20) &&
|
||
(ConfigSpace.SubClass == PCI_SUBCLASS_PRE_20_VGA)) ||
|
||
((ConfigSpace.BaseClass == PCI_CLASS_DISPLAY_CTLR) &&
|
||
(ConfigSpace.SubClass == PCI_SUBCLASS_VID_VGA_CTLR))) {
|
||
|
||
|
||
//
|
||
// Map the VGA registers we are going to use.
|
||
//
|
||
|
||
PhysicalAddress.HighPart = 0;
|
||
PhysicalAddress.LowPart = VGA_STATUS_REGISTER1;
|
||
|
||
BaseReg = VideoPortGetDeviceBase(HwDeviceExtension,
|
||
PhysicalAddress,
|
||
1,
|
||
VIDEO_MEMORY_SPACE_IO);
|
||
|
||
if (BaseReg) {
|
||
|
||
//
|
||
// If we got here the PCI config space for our device indicates
|
||
// we are the VGA, and we were able to map the VGA resources.
|
||
//
|
||
|
||
VgaEnable = DEVICE_VGA_ENABLED;
|
||
|
||
VideoPortFreeDeviceBase(HwDeviceExtension, BaseReg);
|
||
}
|
||
}
|
||
|
||
return VgaEnable;
|
||
}
|
||
|
||
VOID
|
||
pVideoPortDpcDispatcher(
|
||
IN PKDPC Dpc,
|
||
IN PVOID HwDeviceExtension,
|
||
IN PMINIPORT_DPC_ROUTINE DpcRoutine,
|
||
IN PVOID Context
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine handles DPCs and forwards them to the miniport callback
|
||
routine.
|
||
|
||
Arguments:
|
||
|
||
Dpc - The DPC which is executing.
|
||
|
||
HwDeviceExtension - The HwDeviceExtension for the device which scheduled
|
||
the DPC.
|
||
|
||
DpcRoutine - The callback in the miniport which needs to be called.
|
||
|
||
Context - The miniport supplied context.
|
||
|
||
Returns:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
DpcRoutine(HwDeviceExtension, Context);
|
||
}
|
||
|
||
BOOLEAN
|
||
VideoPortQueueDpc(
|
||
IN PVOID HwDeviceExtension,
|
||
IN PMINIPORT_DPC_ROUTINE CallbackRoutine,
|
||
IN PVOID Context
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Allows a miniport driver to queue a DPC.
|
||
|
||
Arguments:
|
||
|
||
HwDeviceExtension - The HwDeviceExtension for the miniport.
|
||
|
||
CallbackRoutine - The entry point within the miniport to call when the DPC
|
||
is scheduled.
|
||
|
||
Context - A miniport supplies context which will be passed to the
|
||
CallbackRoutine.
|
||
|
||
Returns:
|
||
|
||
TRUE if successful,
|
||
FALSE otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
|
||
|
||
return KeInsertQueueDpc(&fdoExtension->Dpc, CallbackRoutine, Context);
|
||
}
|
||
|
||
ULONG
|
||
VpGetDeviceCount(
|
||
IN PVOID HwDeviceExtension
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Allows a miniport driver to queue a DPC.
|
||
|
||
Arguments:
|
||
|
||
HwDeviceExtension - The HwDeviceExtension for the miniport.
|
||
|
||
Returns:
|
||
|
||
The number of started devices.
|
||
|
||
--*/
|
||
|
||
{
|
||
return NumDevicesStarted;
|
||
}
|
||
|
||
VOID
|
||
pVpBugcheckCallback(
|
||
IN KBUGCHECK_CALLBACK_REASON Reason,
|
||
IN PKBUGCHECK_REASON_CALLBACK_RECORD Record,
|
||
IN OUT PVOID ReasonSpecificData,
|
||
IN ULONG ReasonSpecificDataLength
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This callback is called when a bugcheck occurs. It allows the
|
||
videoprt an opportunity to store data which can later be used
|
||
to help diagnose the bugcheck.
|
||
|
||
Arguments:
|
||
|
||
Reason - the reason we are being called
|
||
|
||
Record - a pointer to the bugcheck reason record we set up
|
||
|
||
ReasonSpecificData - pointer to KBUGCHECK_SECONDARY_DUMP_DATA
|
||
|
||
ReasonSpecificDataLength - the size of the reason specific data
|
||
|
||
Returns:
|
||
|
||
None.
|
||
|
||
Notes:
|
||
|
||
This routine can be called at any time, and must not be pageable.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG BugcheckCode;
|
||
PKBUGCHECK_SECONDARY_DUMP_DATA DumpData
|
||
= (PKBUGCHECK_SECONDARY_DUMP_DATA)ReasonSpecificData;
|
||
|
||
//
|
||
// Only handle secondary dumps
|
||
//
|
||
|
||
if (Reason != KbCallbackSecondaryDumpData) {
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Grab the bugcheck code. We only handle EA currently.
|
||
//
|
||
|
||
BugcheckCode = *((PULONG)KiBugCheckData[0]);
|
||
|
||
if (BugcheckCode == 0xEA) {
|
||
pVpGeneralBugcheckHandler(DumpData);
|
||
}
|
||
}
|
||
|
||
VOID
|
||
pVpGeneralBugcheckHandler(
|
||
PKBUGCHECK_SECONDARY_DUMP_DATA DumpData
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine calls all of the hooked bugcheck callbacks,
|
||
and appends the data into the supplied buffer.
|
||
|
||
Arguments:
|
||
|
||
DumpData - pointer to the location in which to store the dump data
|
||
|
||
Returns:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
if (VpBugcheckDeviceObject != NULL) {
|
||
|
||
PFDO_EXTENSION FdoExtension = VpBugcheckDeviceObject->DeviceExtension;
|
||
|
||
//
|
||
// Fill in the GUID, output buffer, and output buffer length
|
||
//
|
||
|
||
DumpData->OutBuffer = VpBugcheckData;
|
||
DumpData->OutBufferLength = FdoExtension->BugcheckDataSize;
|
||
memcpy(&DumpData->Guid, &VpBugcheckGUID, sizeof(VpBugcheckGUID));
|
||
|
||
//
|
||
// Call each "hooked" reason callback entry point
|
||
//
|
||
|
||
if (FdoExtension->BugcheckCallback) {
|
||
|
||
FdoExtension->BugcheckCallback(
|
||
FdoExtension->HwDeviceExtension,
|
||
0xEA,
|
||
VpBugcheckData,
|
||
FdoExtension->BugcheckDataSize);
|
||
}
|
||
}
|
||
}
|
||
|
||
VOID
|
||
VpAcquireLock(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will acquire the global video port lock. This lock
|
||
protects global data structures which are shared across drivers.
|
||
|
||
Arguments:
|
||
|
||
none.
|
||
|
||
Returns:
|
||
|
||
none.
|
||
|
||
--*/
|
||
|
||
{
|
||
KeWaitForSingleObject(
|
||
&VpGlobalLock,
|
||
Executive,
|
||
KernelMode,
|
||
FALSE,
|
||
(PTIME)NULL);
|
||
}
|
||
|
||
VOID
|
||
VpReleaseLock(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will release the global video port lock. This lock
|
||
protects global data structures which are shared across drivers.
|
||
|
||
Arguments:
|
||
|
||
none.
|
||
|
||
Returns:
|
||
|
||
none.
|
||
|
||
--*/
|
||
|
||
{
|
||
KeReleaseMutex(&VpGlobalLock, FALSE);
|
||
}
|
||
|
||
PVOID
|
||
VpAllocateNonPagedPoolPageAligned(
|
||
ULONG Size
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will allocate non-paged pool on a page alignment.
|
||
|
||
Arguments:
|
||
|
||
Size - The number of bytes of memory to allocate.
|
||
|
||
Returns:
|
||
|
||
A pointer to the allocated buffer.
|
||
|
||
--*/
|
||
|
||
{
|
||
PVOID Buffer;
|
||
|
||
if (Size < PAGE_SIZE) {
|
||
Size = PAGE_SIZE;
|
||
}
|
||
|
||
Buffer = ExAllocatePoolWithTag(NonPagedPool, Size, VP_TAG);
|
||
|
||
//
|
||
// Make sure the buffer is page aligned. In current builds,
|
||
// allocating at least 1 page from non-paged pool, will always
|
||
// result in a page aligned allocation.
|
||
//
|
||
// However, since this could change someday, verify that this
|
||
// remains true.
|
||
//
|
||
|
||
if ((ULONG_PTR)Buffer & (PAGE_SIZE - 1)) {
|
||
ExFreePool(Buffer);
|
||
Buffer = NULL;
|
||
}
|
||
|
||
return Buffer;
|
||
}
|
||
|
||
VP_STATUS
|
||
VideoPortRegisterBugcheckCallback(
|
||
IN PVOID HwDeviceExtension,
|
||
IN ULONG BugcheckCode,
|
||
IN PVIDEO_BUGCHECK_CALLBACK Callback,
|
||
IN ULONG BugcheckDataSize
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine allows a video miniport to register for a callback at
|
||
bugcheck time. The driver will then have an opportunity to store
|
||
data that can be used to help diagnose the bugcheck. The data is
|
||
appended to the dump file.
|
||
|
||
Arguments:
|
||
|
||
HwDeviceExtension - a pointer to the device extension
|
||
|
||
BugcheckCode - allows you to specify the bugcheck code you want to
|
||
be notified for.
|
||
|
||
Callback - a pointer to the miniport supplied callback function
|
||
which will be invoked when a bugcheck occurs. The callback function
|
||
must be non-paged, and must not access pageable code or data.
|
||
|
||
BugcheckDataSize - The amount of data the miniport will want to add
|
||
to the minidump.
|
||
|
||
Returns:
|
||
|
||
A status code indicating success or failure.
|
||
|
||
Notes:
|
||
|
||
Currently only bugcheck EA's can be hooked.
|
||
|
||
Currently we limit the data size to 4k.
|
||
|
||
To unhook the callback, the miniport can specify NULL for the callback
|
||
or 0 for the DataSize.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFDO_EXTENSION fdoExtension = GET_FDO_EXT(HwDeviceExtension);
|
||
VP_STATUS Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
//
|
||
// For now let's only support hooking bugcheck EA.
|
||
//
|
||
|
||
if (BugcheckCode != 0xEA) {
|
||
|
||
pVideoDebugPrint((0, "Currently only bugcheck 0xEA can be hooked.\n"));
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
//
|
||
// Force the data size to be a multiple of 16 bytes.
|
||
//
|
||
|
||
BugcheckDataSize = (BugcheckDataSize + 15) & ~15;
|
||
|
||
//
|
||
// The kernel support code only allows 4k per caller for minidumps.
|
||
//
|
||
|
||
if (BugcheckDataSize > MAX_SECONDARY_DUMP_SIZE) {
|
||
|
||
pVideoDebugPrint((0, "There is ~4k limit on bugcheck data size.\n"));
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
//
|
||
// Acquire global videoprt lock, because we will be modifiying
|
||
// global state.
|
||
//
|
||
|
||
VpAcquireLock();
|
||
|
||
//
|
||
// If the Callback is NULL, or the BugcheckDataSize is 0 then
|
||
// they are unregistering the callback.
|
||
//
|
||
|
||
if ((Callback == NULL) || (BugcheckDataSize == 0)) {
|
||
|
||
//
|
||
// Only unregister if they were registered!
|
||
//
|
||
|
||
if (fdoExtension->BugcheckCallback) {
|
||
|
||
fdoExtension->BugcheckCallback = NULL;
|
||
fdoExtension->BugcheckDataSize = 0;
|
||
}
|
||
|
||
Status = NO_ERROR;
|
||
|
||
} else {
|
||
|
||
if (VpBugcheckData == NULL) {
|
||
|
||
//
|
||
// Try to acquire a large enough buffer for the bugcheck data for
|
||
// this driver and all other drivers already registered
|
||
//
|
||
|
||
VpBugcheckData = VpAllocateNonPagedPoolPageAligned(PAGE_SIZE);
|
||
|
||
}
|
||
|
||
//
|
||
// If the allocation succeeded then register the bugcheck
|
||
// callback
|
||
//
|
||
|
||
if (VpBugcheckData) {
|
||
|
||
//
|
||
// Update the fdoExtension to indicate the callback is hooked.
|
||
//
|
||
|
||
fdoExtension->BugcheckCallback = Callback;
|
||
fdoExtension->BugcheckDataSize = BugcheckDataSize;
|
||
|
||
Status = NO_ERROR;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Release the global videoprt lock
|
||
//
|
||
|
||
VpReleaseLock();
|
||
|
||
return Status;
|
||
}
|
||
|
||
static
|
||
VOID
|
||
FreeDumpFileDacl(
|
||
PACL pDacl
|
||
)
|
||
{
|
||
if (pDacl) ExFreePool(pDacl);
|
||
}
|
||
|
||
static
|
||
PACL
|
||
CreateDumpFileDacl(
|
||
VOID
|
||
)
|
||
{
|
||
ULONG ulDacLength = sizeof(ACL)
|
||
+ 2 * sizeof(ACCESS_ALLOWED_ACE)
|
||
- 2 * sizeof(ULONG)
|
||
+ RtlLengthSid(SeExports->SeLocalSystemSid)
|
||
+ RtlLengthSid(SeExports->SeCreatorOwnerSid);
|
||
|
||
PACL pDacl = (PACL)ExAllocatePoolWithTag(PagedPool, ulDacLength, VP_TAG);
|
||
|
||
if (pDacl &&
|
||
NT_SUCCESS(RtlCreateAcl(pDacl, ulDacLength, ACL_REVISION)) &&
|
||
NT_SUCCESS(RtlAddAccessAllowedAce(pDacl,
|
||
ACL_REVISION,
|
||
GENERIC_ALL,
|
||
SeExports->SeLocalSystemSid)) &&
|
||
NT_SUCCESS(RtlAddAccessAllowedAce(pDacl,
|
||
ACL_REVISION,
|
||
DELETE,
|
||
SeExports->SeCreatorOwnerSid)))
|
||
{
|
||
return pDacl;
|
||
}
|
||
|
||
FreeDumpFileDacl(pDacl);
|
||
return NULL;
|
||
}
|
||
|
||
static
|
||
BOOLEAN
|
||
InitDumpFileSid(
|
||
PSID pSid,
|
||
PACL pDacl
|
||
)
|
||
{
|
||
return (pSid &&
|
||
pDacl &&
|
||
NT_SUCCESS(RtlCreateSecurityDescriptor(pSid, SECURITY_DESCRIPTOR_REVISION)) &&
|
||
NT_SUCCESS(RtlSetDaclSecurityDescriptor(pSid, TRUE, pDacl,FALSE)));
|
||
}
|
||
|
||
VOID
|
||
pVpWriteFile(
|
||
PWSTR pwszFileName,
|
||
PVOID pvBuffer,
|
||
ULONG ulSize
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called when we are trying to recover from a bugcheck
|
||
EA.
|
||
|
||
Arguments:
|
||
|
||
pwszFileName - name of dump file
|
||
pvBuffer - data to write
|
||
ulSize - size of the data to data
|
||
|
||
Returns:
|
||
|
||
none.
|
||
|
||
Notes:
|
||
|
||
This routine can be pagable because it will be called at passive level.
|
||
|
||
--*/
|
||
|
||
{
|
||
SECURITY_DESCRIPTOR Sid;
|
||
PACL pDacl = CreateDumpFileDacl();
|
||
|
||
if (InitDumpFileSid(&Sid, pDacl)) {
|
||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||
UNICODE_STRING UnicodeString;
|
||
HANDLE FileHandle;
|
||
NTSTATUS Status;
|
||
IO_STATUS_BLOCK IoStatusBlock;
|
||
|
||
RtlInitUnicodeString(&UnicodeString,
|
||
pwszFileName);
|
||
|
||
InitializeObjectAttributes(&ObjectAttributes,
|
||
&UnicodeString,
|
||
OBJ_CASE_INSENSITIVE,
|
||
(HANDLE) NULL,
|
||
&Sid);
|
||
|
||
if (NT_SUCCESS(ZwCreateFile(&FileHandle,
|
||
FILE_GENERIC_WRITE,
|
||
&ObjectAttributes,
|
||
&IoStatusBlock,
|
||
NULL,
|
||
FILE_ATTRIBUTE_HIDDEN,
|
||
0, // exclusive
|
||
FILE_SUPERSEDE,
|
||
FILE_SYNCHRONOUS_IO_NONALERT |
|
||
FILE_WRITE_THROUGH,
|
||
NULL,
|
||
0)))
|
||
{
|
||
ZwWriteFile(FileHandle,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
&IoStatusBlock,
|
||
pvBuffer,
|
||
ulSize,
|
||
NULL,
|
||
NULL);
|
||
|
||
//
|
||
// Close the file.
|
||
//
|
||
|
||
ZwClose(FileHandle);
|
||
}
|
||
}
|
||
|
||
FreeDumpFileDacl(pDacl);
|
||
}
|