windows-nt/Source/XPSP1/NT/drivers/video/ms/vgarisc/disp/hardware.c
2020-09-26 16:20:57 +08:00

601 lines
19 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"
// Values for the internal, EGA-compatible palette.
static WORD gPaletteBuffer[] = {
16, // 16 entries
0, // start with first palette register
// On the VGA, the palette contains indices into the array of color DACs.
// Since we can program the DACs as we please, we'll just put all the indices
// down at the beginning of the DAC array (that is, pass pixel values through
// the internal palette unchanged).
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
};
// These are the values for the first 16 DAC registers, the only ones we'll
// work with. These correspond to the RGB colors (6 bits for each primary, with
// the fourth entry unused) for pixel values 0-15.
static BYTE gColorBuffer[] = {
16, // 16 entries
0,
0,
0, // start with first palette register
0x00, 0x00, 0x00, 0x00, // black
0x2A, 0x00, 0x15, 0x00, // red
0x00, 0x2A, 0x15, 0x00, // green
0x2A, 0x2A, 0x15, 0x00, // mustard/brown
0x00, 0x00, 0x2A, 0x00, // blue
0x2A, 0x15, 0x2A, 0x00, // magenta
0x15, 0x2A, 0x2A, 0x00, // cyan
0x21, 0x22, 0x23, 0x00, // dark gray 2A
0x30, 0x31, 0x32, 0x00, // light gray 39
0x3F, 0x00, 0x00, 0x00, // bright red
0x00, 0x3F, 0x00, 0x00, // bright green
0x3F, 0x3F, 0x00, 0x00, // bright yellow
0x00, 0x00, 0x3F, 0x00, // bright blue
0x3F, 0x00, 0x3F, 0x00, // bright magenta
0x00, 0x3F, 0x3F, 0x00, // bright cyan
0x3F, 0x3F, 0x3F, 0x00 // bright white
};
/******************************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;
pjBase = ppdev->pjBase;
if (bEnable)
{
// 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;
}
// Set up the internal palette.
if (EngDeviceIoControl(ppdev->hDriver,
IOCTL_VIDEO_SET_PALETTE_REGISTERS,
(PVOID) gPaletteBuffer, // input buffer
sizeof(gPaletteBuffer),
NULL, // output buffer
0,
&ReturnedDataLength))
{
DISPDBG((0, "bAssertModeHardware - Failed VIDEO_SET_PALETTE_REGISTERS"));
return(FALSE);
}
// Set up the DAC.
if (EngDeviceIoControl(ppdev->hDriver,
IOCTL_VIDEO_SET_COLOR_REGISTERS,
(PVOID) gColorBuffer, // input buffer
sizeof(gColorBuffer),
NULL, // output buffer
0,
&ReturnedDataLength))
{
DISPDBG((0, "bAssertModeHardware - Failed VIDEO_SET_COLOR_REGISTERS"));
return(FALSE);
}
// Initialize sequencer to its defaults (all planes enabled, index
// pointing to Map Mask).
OUT_WORD(pjBase, VGA_BASE + SEQ_ADDR, (MM_ALL << 8) + SEQ_MAP_MASK);
// Initialize graphics controller to its defaults (set/reset disabled for
// all planes, no rotation & ALU function == replace, write mode 0 & read
// mode 0, color compare ignoring all planes (read mode 1 reads always
// return 0ffh, handy for ANDing), and the bit mask == 0ffh, gating all
// bytes from the CPU.
OUT_WORD(pjBase, VGA_BASE + GRAF_ADDR, GRAF_ENAB_SR);
OUT_WORD(pjBase, VGA_BASE + GRAF_ADDR, (DR_SET << 8) + GRAF_DATA_ROT);
OUT_WORD(pjBase, VGA_BASE + GRAF_ADDR, ((M_PROC_WRITE | M_DATA_READ) << 8)
+ GRAF_MODE);
OUT_WORD(pjBase, VGA_BASE + GRAF_ADDR, GRAF_CDC);
OUT_WORD(pjBase, VGA_BASE + GRAF_ADDR, (0xffL << 8) + GRAF_BIT_MASK);
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;
// 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))
{
DISPDBG((0, "bEnableHardware - Initialization error mapping IO port base"));
goto ReturnFalse;
}
ppdev->pjBase = (UCHAR*) VideoAccessRange.VirtualAddress;
// 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))
{
DISPDBG((0, "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->pjScreen = (BYTE*) VideoMemoryInfo.FrameBufferBase;
if (EngDeviceIoControl(ppdev->hDriver,
IOCTL_VIDEO_QUERY_CURRENT_MODE,
NULL,
0,
&VideoModeInfo,
sizeof(VideoModeInfo),
&ReturnedDataLength))
{
DISPDBG((0, "bEnableHardware - failed VIDEO_QUERY_CURRENT_MODE"));
goto ReturnFalse;
}
// Store the width of the screen in bytes
ppdev->lDelta = VideoModeInfo.ScreenStride;
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;
if ((VideoMemory.RequestedVirtualAddress = ppdev->pjScreen) != NULL) {
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((VideoMemory.RequestedVirtualAddress = ppdev->pjBase) != INVALID_BASE_ADDRESS)
{
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"));
}
ppdev->pjBase = INVALID_BASE_ADDRESS;
}
}
/******************************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.
*
\**************************************************************************/
#define STRIP_SIZE 32
// This little macro returns the 'PositionInNibble' bit of the
// 'NibbleNumber' nibble of the given 'Dword', and aligns it so that
// it's in the 'PositionInResult' bit of the result. Numbering is done
// in the order '7 6 5 4 3 2 1 0'.
//
// Given constants for everything but 'Dword', this will amount to an
// AND and a SHIFT.
#define BITPOS(Dword, PositionInNibble, NibbleNumber, PositionInResult) \
(WORD) (((((PositionInNibble) + (NibbleNumber) * 4) > (PositionInResult)) ? \
(((Dword) & (1 << ((PositionInNibble) + (NibbleNumber) * 4))) \
>> ((PositionInNibble) + (NibbleNumber) * 4 - (PositionInResult))) : \
(((Dword) & (1 << ((PositionInNibble) + (NibbleNumber) * 4))) \
<< ((PositionInResult) - (PositionInNibble) - (NibbleNumber) * 4))))
VOID vUpdate(PDEV* ppdev, RECTL* prcl, CLIPOBJ* pco)
{
BYTE* pjBase;
RECTL rcl;
SURFOBJ* pso;
LONG cy;
LONG cyThis;
LONG cw;
ULONG* pulSrcStart;
ULONG* pulSrc;
WORD* pwDstStart;
WORD* pwDst;
LONG i;
LONG j;
ULONG ul;
WORD w;
LONG lSrcDelta;
LONG lDstDelta;
LONG lSrcSkip;
LONG lDstSkip;
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 words so that we don't have to do any read-modify-write
// operations.
rcl.left = (rcl.left) & ~15;
rcl.right = (rcl.right + 15) & ~15;
pso = ppdev->pso;
lSrcDelta = pso->lDelta;
pulSrcStart = (ULONG*) ((BYTE*) pso->pvScan0 + (rcl.top * lSrcDelta)
+ (rcl.left >> 1));
lDstDelta = ppdev->lDelta;
pwDstStart = (WORD*) (ppdev->pjScreen + (rcl.top * lDstDelta)
+ (rcl.left >> 3));
cy = (rcl.bottom - rcl.top);
cw = (rcl.right - rcl.left) >> 4;
lSrcSkip = lSrcDelta - (8 * cw);
lDstSkip = lDstDelta - (2 * cw);
do {
cyThis = STRIP_SIZE;
cy -= STRIP_SIZE;
if (cy < 0)
cyThis += cy;
// Map in plane 0:
OUT_BYTE(pjBase, VGA_BASE + SEQ_DATA, MM_C0);
pwDst = pwDstStart;
pulSrc = pulSrcStart;
for (j = cyThis; j != 0; j--)
{
for (i = cw; i != 0; i--)
{
ul = *(pulSrc);
w = BITPOS(ul, 0, 6, 0) |
BITPOS(ul, 0, 7, 1) |
BITPOS(ul, 0, 4, 2) |
BITPOS(ul, 0, 5, 3) |
BITPOS(ul, 0, 2, 4) |
BITPOS(ul, 0, 3, 5) |
BITPOS(ul, 0, 0, 6) |
BITPOS(ul, 0, 1, 7);
ul = *(pulSrc + 1);
w |= BITPOS(ul, 0, 6, 8) |
BITPOS(ul, 0, 7, 9) |
BITPOS(ul, 0, 4, 10) |
BITPOS(ul, 0, 5, 11) |
BITPOS(ul, 0, 2, 12) |
BITPOS(ul, 0, 3, 13) |
BITPOS(ul, 0, 0, 14) |
BITPOS(ul, 0, 1, 15);
WRITE_WORD(pwDst, w);
pwDst += 1;
pulSrc += 2;
}
pwDst = (WORD*) ((BYTE*) pwDst + lDstSkip);
pulSrc = (ULONG*) ((BYTE*) pulSrc + lSrcSkip);
}
// Map in plane 1:
OUT_BYTE(pjBase, VGA_BASE + SEQ_DATA, MM_C1);
pwDst = pwDstStart;
pulSrc = pulSrcStart;
for (j = cyThis; j != 0; j--)
{
for (i = cw; i != 0; i--)
{
ul = *(pulSrc);
w = BITPOS(ul, 1, 6, 0) |
BITPOS(ul, 1, 7, 1) |
BITPOS(ul, 1, 4, 2) |
BITPOS(ul, 1, 5, 3) |
BITPOS(ul, 1, 2, 4) |
BITPOS(ul, 1, 3, 5) |
BITPOS(ul, 1, 0, 6) |
BITPOS(ul, 1, 1, 7);
ul = *(pulSrc + 1);
w |= BITPOS(ul, 1, 6, 8) |
BITPOS(ul, 1, 7, 9) |
BITPOS(ul, 1, 4, 10) |
BITPOS(ul, 1, 5, 11) |
BITPOS(ul, 1, 2, 12) |
BITPOS(ul, 1, 3, 13) |
BITPOS(ul, 1, 0, 14) |
BITPOS(ul, 1, 1, 15);
WRITE_WORD(pwDst, w);
pwDst += 1;
pulSrc += 2;
}
pwDst = (WORD*) ((BYTE*) pwDst + lDstSkip);
pulSrc = (ULONG*) ((BYTE*) pulSrc + lSrcSkip);
}
// Map in plane 2:
OUT_BYTE(pjBase, VGA_BASE + SEQ_DATA, MM_C2);
pwDst = pwDstStart;
pulSrc = pulSrcStart;
for (j = cyThis; j != 0; j--)
{
for (i = cw; i != 0; i--)
{
ul = *(pulSrc);
w = BITPOS(ul, 2, 6, 0) |
BITPOS(ul, 2, 7, 1) |
BITPOS(ul, 2, 4, 2) |
BITPOS(ul, 2, 5, 3) |
BITPOS(ul, 2, 2, 4) |
BITPOS(ul, 2, 3, 5) |
BITPOS(ul, 2, 0, 6) |
BITPOS(ul, 2, 1, 7);
ul = *(pulSrc + 1);
w |= BITPOS(ul, 2, 6, 8) |
BITPOS(ul, 2, 7, 9) |
BITPOS(ul, 2, 4, 10) |
BITPOS(ul, 2, 5, 11) |
BITPOS(ul, 2, 2, 12) |
BITPOS(ul, 2, 3, 13) |
BITPOS(ul, 2, 0, 14) |
BITPOS(ul, 2, 1, 15);
WRITE_WORD(pwDst, w);
pwDst += 1;
pulSrc += 2;
}
pwDst = (WORD*) ((BYTE*) pwDst + lDstSkip);
pulSrc = (ULONG*) ((BYTE*) pulSrc + lSrcSkip);
}
// Map in plane 3:
OUT_BYTE(pjBase, VGA_BASE + SEQ_DATA, MM_C3);
pwDst = pwDstStart;
pulSrc = pulSrcStart;
for (j = cyThis; j != 0; j--)
{
for (i = cw; i != 0; i--)
{
ul = *(pulSrc);
w = BITPOS(ul, 3, 6, 0) |
BITPOS(ul, 3, 7, 1) |
BITPOS(ul, 3, 4, 2) |
BITPOS(ul, 3, 5, 3) |
BITPOS(ul, 3, 2, 4) |
BITPOS(ul, 3, 3, 5) |
BITPOS(ul, 3, 0, 6) |
BITPOS(ul, 3, 1, 7);
ul = *(pulSrc + 1);
w |= BITPOS(ul, 3, 6, 8) |
BITPOS(ul, 3, 7, 9) |
BITPOS(ul, 3, 4, 10) |
BITPOS(ul, 3, 5, 11) |
BITPOS(ul, 3, 2, 12) |
BITPOS(ul, 3, 3, 13) |
BITPOS(ul, 3, 0, 14) |
BITPOS(ul, 3, 1, 15);
WRITE_WORD(pwDst, w);
pwDst += 1;
pulSrc += 2;
}
pwDst = (WORD*) ((BYTE*) pwDst + lDstSkip);
pulSrc = (ULONG*) ((BYTE*) pulSrc + lSrcSkip);
}
// Get ready for next strip:
pulSrcStart = (ULONG*) ((BYTE*) pulSrcStart + (cyThis * lSrcDelta));
pwDstStart = (WORD*) ((BYTE*) pwDstStart + (cyThis * lDstDelta));
} while (cy > 0);
}