373 lines
10 KiB
C
373 lines
10 KiB
C
/******************************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);
|
|
}
|