windows-nt/Source/XPSP1/NT/drivers/video/ms/modex/disp/hardware.c

373 lines
10 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/******************************Module*Header*******************************\
* Module Name: hardware.c
*
* Contains all the code that touches the display hardware.
*
* Copyright (c) 1994-1995 Microsoft Corporation
\**************************************************************************/
#include "precomp.h"
/******************************Public*Routine******************************\
* BOOL bAssertModeHardware
*
* Sets the appropriate hardware state for graphics mode or full-screen.
*
\**************************************************************************/
BOOL bAssertModeHardware(
PDEV* ppdev,
BOOL bEnable)
{
DWORD ReturnedDataLength;
BYTE* pjBase;
RECTL rcl;
pjBase = ppdev->pjBase;
if (bEnable)
{
// Reset some state:
ppdev->cjVgaOffset = 0;
ppdev->iVgaPage = 0;
ppdev->fpScreenOffset = 0;
// Set the desired mode.
if (EngDeviceIoControl(ppdev->hDriver,
IOCTL_VIDEO_SET_CURRENT_MODE,
&ppdev->ulMode, // input buffer
sizeof(VIDEO_MODE),
NULL,
0,
&ReturnedDataLength))
{
DISPDBG((0, "bAssertModeHardware - Failed VIDEO_SET_CURRENT_MODE"));
goto ReturnFalse;
}
// Now blank the screen:
rcl.left = 0;
rcl.top = 0;
rcl.right = ppdev->cxScreen;
rcl.bottom = ppdev->cyScreen;
vUpdate(ppdev, &rcl, NULL);
DISPDBG((5, "Passed bAssertModeHardware"));
}
else
{
// Call the kernel driver to reset the device to a known state.
// NTVDM will take things from there:
if (EngDeviceIoControl(ppdev->hDriver,
IOCTL_VIDEO_RESET_DEVICE,
NULL,
0,
NULL,
0,
&ReturnedDataLength))
{
DISPDBG((0, "bAssertModeHardware - Failed reset IOCTL"));
goto ReturnFalse;
}
}
return(TRUE);
ReturnFalse:
DISPDBG((0, "Failed bAssertModeHardware"));
return(FALSE);
}
/******************************Public*Routine******************************\
* BOOL bEnableHardware
*
* Puts the hardware into the requested mode and initializes it.
*
* Note: Should be called before any access is done to the hardware from
* the display driver.
*
\**************************************************************************/
BOOL bEnableHardware(
PDEV* ppdev)
{
VIDEO_MEMORY VideoMemory;
VIDEO_MEMORY_INFORMATION VideoMemoryInfo;
VIDEO_MODE_INFORMATION VideoModeInfo;
DWORD ReturnedDataLength;
VIDEO_PUBLIC_ACCESS_RANGES VideoAccessRange;
DWORD status;
#if defined(_X86_)
ppdev->pjBase = NULL;
#else
// Map io ports into virtual memory:
VideoMemory.RequestedVirtualAddress = NULL;
if (EngDeviceIoControl(ppdev->hDriver,
IOCTL_VIDEO_QUERY_PUBLIC_ACCESS_RANGES,
NULL, // input buffer
0,
&VideoAccessRange, // output buffer
sizeof (VideoAccessRange),
&ReturnedDataLength))
{
RIP("bEnableHardware - Initialization error mapping IO port base");
goto ReturnFalse;
}
ppdev->pjBase = (UCHAR*) VideoAccessRange.VirtualAddress;
#endif
// Set the desired mode. (Must come before IOCTL_VIDEO_MAP_VIDEO_MEMORY;
// that IOCTL returns information for the current mode, so there must be a
// current mode for which to return information.)
if (EngDeviceIoControl(ppdev->hDriver,
IOCTL_VIDEO_SET_CURRENT_MODE,
&ppdev->ulMode, // input buffer
sizeof(VIDEO_MODE),
NULL,
0,
&ReturnedDataLength))
{
RIP("bEnableHardware - Set current mode");
goto ReturnFalse;
}
// Get the linear memory address range.
VideoMemory.RequestedVirtualAddress = NULL;
if (EngDeviceIoControl(ppdev->hDriver,
IOCTL_VIDEO_MAP_VIDEO_MEMORY,
&VideoMemory, // input buffer
sizeof(VIDEO_MEMORY),
&VideoMemoryInfo, // output buffer
sizeof(VideoMemoryInfo),
&ReturnedDataLength))
{
DISPDBG((0, "bEnableHardware - Error mapping buffer address"));
goto ReturnFalse;
}
DISPDBG((1, "FrameBufferBase: %lx", VideoMemoryInfo.FrameBufferBase));
// Record the Frame Buffer Linear Address.
ppdev->pjVga = (BYTE*) VideoMemoryInfo.FrameBufferBase;
// Store the width of the screen in bytes, per-plane:
ppdev->lVgaDelta = ppdev->cxScreen / 4;
if (!bAssertModeHardware(ppdev, TRUE))
goto ReturnFalse;
DISPDBG((5, "Passed bEnableHardware"));
return(TRUE);
ReturnFalse:
DISPDBG((0, "Failed bEnableHardware"));
return(FALSE);
}
/******************************Public*Routine******************************\
* VOID vDisableHardware
*
* Undoes anything done in bEnableHardware.
*
* Note: In an error case, we may call this before bEnableHardware is
* completely done.
*
\**************************************************************************/
VOID vDisableHardware(
PDEV* ppdev)
{
DWORD ReturnedDataLength;
VIDEO_MEMORY VideoMemory;
VideoMemory.RequestedVirtualAddress = ppdev->pjVga;
if (EngDeviceIoControl(ppdev->hDriver,
IOCTL_VIDEO_UNMAP_VIDEO_MEMORY,
&VideoMemory,
sizeof(VIDEO_MEMORY),
NULL,
0,
&ReturnedDataLength))
{
DISPDBG((0, "vDisableHardware failed IOCTL_VIDEO_UNMAP_VIDEO"));
}
#if !defined(_X86_)
VideoMemory.RequestedVirtualAddress = ppdev->pjBase;
if (EngDeviceIoControl(ppdev->hDriver,
IOCTL_VIDEO_FREE_PUBLIC_ACCESS_RANGES,
&VideoMemory,
sizeof(VIDEO_MEMORY),
NULL,
0,
&ReturnedDataLength))
{
DISPDBG((0, "vDisableHardware failed IOCTL_VIDEO_FREE_PUBLIC_ACCESS"));
}
#endif
}
/******************************Public*Routine******************************\
* VOID vUpdate(ppdev, prcl, pco)
*
* Updates the screen from the DIB surface for the given rectangle.
* Increases the rectangle size if necessary for easy alignment.
*
* NOTE: Life is made complicated by the fact that we are faking DirectDraw
* 'flip' surfaces. When we're asked by GDI to draw, it should be
* copied from the shadow buffer to the physical screen only if
* DirectDraw is currently 'flipped' to the primary surface.
*
\**************************************************************************/
VOID vUpdate(PDEV* ppdev, RECTL* prcl, CLIPOBJ* pco)
{
BYTE* pjBase;
RECTL rcl;
SURFOBJ* pso;
LONG lSrcDelta;
BYTE* pjSrcStart;
BYTE* pjSrc;
LONG lDstDelta;
BYTE* pjDstStart;
BYTE* pjDst;
ULONG cy;
ULONG cDwordsPerPlane;
ULONG iPage;
ULONG i;
ULONG ul;
pjBase = ppdev->pjBase;
if ((pco == NULL) || (pco->iDComplexity == DC_TRIVIAL))
{
// We have to clip to the screen dimensions because we may have
// been a bit loose when we guessed the bounds of the drawing:
rcl.left = max(0, prcl->left);
rcl.top = max(0, prcl->top);
rcl.right = min(ppdev->cxScreen, prcl->right);
rcl.bottom = min(ppdev->cyScreen, prcl->bottom);
}
else
{
// We may as well save ourselves some blting by clipping to
// the clip object's maximum extent. The clip object's bounds
// are guaranteed to be contained within the dimensions of the
// screen:
rcl.left = max(pco->rclBounds.left, prcl->left);
rcl.top = max(pco->rclBounds.top, prcl->top);
rcl.right = min(pco->rclBounds.right, prcl->right);
rcl.bottom = min(pco->rclBounds.bottom, prcl->bottom);
}
// Be paranoid:
if ((rcl.left >= rcl.right) || (rcl.top >= rcl.bottom))
return;
// Align to dwords to keep things simple.
rcl.left = (rcl.left) & ~15;
rcl.right = (rcl.right + 15) & ~15;
lSrcDelta = ppdev->lScreenDelta;
pjSrcStart = ppdev->pjScreen + ppdev->fpScreenOffset
+ (rcl.top * lSrcDelta)
+ rcl.left;
lDstDelta = ppdev->lVgaDelta;
pjDstStart = ppdev->pjVga + ppdev->cjVgaOffset
+ (rcl.top * lDstDelta)
+ (rcl.left >> 2);
cy = (rcl.bottom - rcl.top);
cDwordsPerPlane = (rcl.right - rcl.left) >> 4;
lSrcDelta -= 4; // Account for per-plane increment
WRITE_PORT_UCHAR(pjBase + VGA_BASE + SEQ_ADDR, SEQ_MAP_MASK);
do {
for (iPage = 0; iPage < 4; iPage++, pjSrcStart++)
{
WRITE_PORT_UCHAR(pjBase + VGA_BASE + SEQ_DATA, 1 << iPage);
pjSrc = pjSrcStart;
pjDst = pjDstStart;
#if defined(_X86_)
_asm {
mov esi,pjSrcStart
mov edi,pjDstStart
mov ecx,cDwordsPerPlane
PixelLoop:
mov al,[esi+8]
mov ah,[esi+12]
shl eax,16
mov al,[esi]
mov ah,[esi+4]
mov [edi],eax
add edi,4
add esi,16
dec ecx
jnz PixelLoop
}
#else
for (i = cDwordsPerPlane; i != 0; i--)
{
ul = (*(pjSrc))
| (*(pjSrc + 4) << 8)
| (*(pjSrc + 8) << 16)
| (*(pjSrc + 12) << 24);
WRITE_REGISTER_ULONG((ULONG*) pjDst, ul);
pjDst += 4;
pjSrc += 16;
}
#endif
}
pjSrcStart += lSrcDelta;
pjDstStart += lDstDelta;
} while (--cy != 0);
}