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.
1522 lines
53 KiB
1522 lines
53 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: bank.c
|
|
*
|
|
* Functions to control 64k color VGA banking.
|
|
*
|
|
* Currently doesn't handle or even detect broken rasters; assumes broken
|
|
* rasters, if present, are off the right side of the visible bitmap.
|
|
*
|
|
* Copyright (c) 1992 Microsoft Corporation
|
|
\**************************************************************************/
|
|
|
|
#include "driver.h"
|
|
#include "limits.h"
|
|
|
|
VOID vBankErrorTrap(PPDEV, ULONG, BANK_JUST);
|
|
VOID vBank2Window(PPDEV, ULONG, BANK_JUST, ULONG);
|
|
VOID vBank2Window2RW(PPDEV, ULONG, BANK_JUST, ULONG);
|
|
VOID vBank2Window1RW(PPDEV, ULONG, BANK_JUST, ULONG);
|
|
VOID vBank1Window2RW(PPDEV, ULONG, BANK_JUST);
|
|
VOID vBank1Window(PPDEV, ULONG, BANK_JUST);
|
|
VOID vPlanar2Window(PPDEV, ULONG, BANK_JUST, ULONG);
|
|
VOID vPlanar2Window2RW(PPDEV, ULONG, BANK_JUST, ULONG);
|
|
VOID vPlanar2Window1RW(PPDEV, ULONG, BANK_JUST, ULONG);
|
|
VOID vPlanar1Window2RW(PPDEV, ULONG, BANK_JUST);
|
|
VOID vPlanar1Window(PPDEV, ULONG, BANK_JUST);
|
|
|
|
/******************************Public*Routine******************************\
|
|
* bInitializeNonPlanar(ppdev, pBankInfo)
|
|
*
|
|
* Initialize for non-planar mode banking.
|
|
*
|
|
* NOTE: Allocates ppdev->pbiBankInfo and ppdev->pjJustifyTopBank buffers!
|
|
\**************************************************************************/
|
|
|
|
BOOL bInitializeNonPlanar(PPDEV ppdev, VIDEO_BANK_SELECT* pBankInfo)
|
|
{
|
|
LONG lTotalScans;
|
|
LONG lTotalBanks;
|
|
ULONG cjBankSize;
|
|
|
|
ULONG cjGranularity = pBankInfo->Granularity;
|
|
LONG lDelta = pBankInfo->BitmapWidthInBytes;
|
|
ULONG cjBitmapSize = pBankInfo->BitmapSize;
|
|
|
|
ASSERTVGA(cjBitmapSize >= ppdev->cyScreen * lDelta, "Not enough vram");
|
|
|
|
// Set up for non-planar banking:
|
|
|
|
ppdev->lNextScan = lDelta;
|
|
ppdev->vbtBankingType = pBankInfo->BankingType;
|
|
|
|
ppdev->pfnBankSwitchCode =
|
|
(PFN) (((BYTE*)pBankInfo) + pBankInfo->CodeOffset);
|
|
|
|
// Set all clip rects to invalid; they'll be updated when the first
|
|
// bank is mapped in
|
|
|
|
ppdev->rcl1WindowClip.bottom = -1;
|
|
ppdev->rcl2WindowClip[0].bottom = -1;
|
|
ppdev->rcl2WindowClip[1].bottom = -1;
|
|
|
|
// Set up to call the appropriate banking control routines
|
|
|
|
switch(pBankInfo->BankingType)
|
|
{
|
|
case VideoBanked1RW:
|
|
ppdev->pfnBankControl = vBank1Window;
|
|
ppdev->pfnBankControl2Window = vBank2Window1RW;
|
|
break;
|
|
|
|
case VideoBanked1R1W:
|
|
ppdev->pfnBankControl = vBank1Window;
|
|
ppdev->pfnBankControl2Window = vBank2Window;
|
|
break;
|
|
|
|
case VideoBanked2RW:
|
|
ppdev->pfnBankControl = vBank1Window2RW;
|
|
ppdev->pfnBankControl2Window = vBank2Window2RW;
|
|
|
|
// Offset from one bank index to next to make two 32k banks
|
|
// appear to be one seamless 64k bank:
|
|
|
|
ppdev->ulBank2RWSkip = BANK_SIZE_2RW_WINDOW / cjGranularity;
|
|
break;
|
|
|
|
default:
|
|
RIP("Bad BankingType");
|
|
return(FALSE);
|
|
}
|
|
|
|
// Set up the bank control tables with clip rects for banks
|
|
// Note: lTotalBanks is generally an overestimate when granularity
|
|
// is less than window size, because we ignore any banks after the
|
|
// first one that includes the last scan line of the bitmap. A bit
|
|
// of memory could be saved by sizing lTotalBanks exactly. Note too,
|
|
// though, that the 2 RW window case may require more entries then,
|
|
// because its windows are shorter, so you'd have to make sure there
|
|
// were enough entries for the 2 RW window case, or recalculate
|
|
// lTotalBanks for the 2 RW case
|
|
|
|
lTotalBanks = (cjBitmapSize + cjGranularity - 1) / cjGranularity;
|
|
lTotalScans = cjBitmapSize / lDelta;
|
|
|
|
ppdev->cTotalScans = lTotalScans;
|
|
ppdev->pbiBankInfo = (PBANK_INFO) EngAllocMem(FL_ZERO_MEMORY,
|
|
lTotalBanks * sizeof(BANK_INFO), ALLOC_TAG);
|
|
if (ppdev->pbiBankInfo == NULL)
|
|
{
|
|
DISPDBG((0, "VGA64K: Couldn't get memory for bank info"));
|
|
return(FALSE);
|
|
}
|
|
|
|
ppdev->pjJustifyTopBank = (BYTE*) EngAllocMem(0, lTotalScans, ALLOC_TAG);
|
|
if (ppdev->pjJustifyTopBank == NULL)
|
|
{
|
|
DISPDBG((0, "VGA64K: Couldn't get memory for JustifyTopBank table"));
|
|
return(FALSE);
|
|
}
|
|
|
|
// For 2 RW windows, windows are assumed to be 32k in size, otherwise
|
|
// assumed to be 64k:
|
|
|
|
if (pBankInfo->BankingType == VideoBanked2RW)
|
|
cjBankSize = BANK_SIZE_2RW_WINDOW;
|
|
else
|
|
cjBankSize = BANK_SIZE_1_WINDOW;
|
|
|
|
// if ((cjGranularity + lDelta) >= cjBankSize &&
|
|
// (cjGranularity % lDelta) != 0)
|
|
// {
|
|
// // Oh no, we've got broken rasters (where a scan line crosses
|
|
// // a bank boundary):
|
|
//
|
|
// RIP("Oops, broken rasters not yet handled");
|
|
// return(FALSE);
|
|
// }
|
|
// else
|
|
{
|
|
// We now fill in the scan-to-bank look-up and bank tables:
|
|
|
|
LONG iScan = 0;
|
|
ULONG iBank = 0;
|
|
ULONG cjScan = 0;
|
|
ULONG cjNextBank = cjGranularity;
|
|
ULONG cjEndOfBank = cjBankSize;
|
|
PBANK_INFO pbiWorking = ppdev->pbiBankInfo;
|
|
|
|
while (TRUE)
|
|
{
|
|
pbiWorking->ulBankOffset = cjNextBank - cjGranularity;
|
|
|
|
// There are no broken rasters (or if they are, they're off the
|
|
// right edge of the visible bitmap), so don't worry about left and
|
|
// right edges:
|
|
|
|
pbiWorking->rclBankBounds.left = LONG_MIN + 1; // +1 to avoid
|
|
// compiler warn
|
|
pbiWorking->rclBankBounds.right = LONG_MAX;
|
|
pbiWorking->rclBankBounds.top = iScan;
|
|
pbiWorking->rclBankBounds.bottom =
|
|
(cjEndOfBank + lDelta - 1) / lDelta;
|
|
// this rounds up to handle broken rasters that are off the
|
|
// right side of the visible bitmap
|
|
|
|
// We don't need any more banks if we can see to the end
|
|
// of the bitmap with the current bank:
|
|
|
|
if (cjScan + cjBankSize >= cjBitmapSize)
|
|
break;
|
|
|
|
while (cjScan < cjNextBank)
|
|
{
|
|
ppdev->pjJustifyTopBank[iScan++] = (BYTE) iBank;
|
|
cjScan += lDelta;
|
|
}
|
|
|
|
// Get ready for next bank:
|
|
|
|
cjNextBank += cjGranularity;
|
|
cjEndOfBank += cjGranularity;
|
|
pbiWorking++;
|
|
iBank++;
|
|
}
|
|
|
|
// Clean up the last scans:
|
|
|
|
ppdev->iLastBank = iBank;
|
|
pbiWorking->rclBankBounds.bottom = lTotalScans;
|
|
while (iScan < lTotalScans)
|
|
{
|
|
ppdev->pjJustifyTopBank[iScan++] = (BYTE) iBank;
|
|
}
|
|
|
|
// We've just computed the precise table for JustifyTop; we now
|
|
// compute the scan offset for determining JustifyBottom:
|
|
|
|
ASSERTVGA(cjBankSize >= cjGranularity,
|
|
"Device says granularity more than bank size?");
|
|
|
|
ppdev->ulJustifyBottomOffset = (cjBankSize - cjGranularity) / lDelta;
|
|
|
|
// ulJustifyBottomOffset must be less than the number of scans
|
|
// that fit entirely in any bank less the granularity size; if
|
|
// our width doesn't divide evenly into the granularity, we'll
|
|
// have to adjust the value to account for the first scan not
|
|
// starting at offset 0 in any bank:
|
|
|
|
if ((cjGranularity % lDelta) != 0 && ppdev->ulJustifyBottomOffset > 0)
|
|
ppdev->ulJustifyBottomOffset--;
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* bInitializePlanar(ppdev, pBankInfo)
|
|
*
|
|
* Initialize for non-planar mode banking.
|
|
*
|
|
* NOTE: Allocates ppdev->pbiPlanarInfo and ppdev->pjJustifyTopPlanar buffers!
|
|
\**************************************************************************/
|
|
|
|
BOOL bInitializePlanar(PPDEV ppdev, VIDEO_BANK_SELECT* pBankInfo)
|
|
{
|
|
LONG lTotalScans;
|
|
LONG lTotalBanks;
|
|
ULONG cjBankSize;
|
|
ULONG cjGranularity = pBankInfo->PlanarHCGranularity;
|
|
|
|
// Since we're in planar mode, every byte we see actually represents
|
|
// four bytes of video memory:
|
|
|
|
LONG lDelta = pBankInfo->BitmapWidthInBytes / 4;
|
|
ULONG cjBitmapSize = pBankInfo->BitmapSize / 4;
|
|
|
|
ppdev->fl |= DRIVER_PLANAR_CAPABLE;
|
|
|
|
// Set all clip rects to invalid; they'll be updated when the first
|
|
// bank is mapped in
|
|
|
|
ppdev->rcl1PlanarClip.bottom = -1;
|
|
ppdev->rcl2PlanarClip[0].bottom = -1;
|
|
ppdev->rcl2PlanarClip[1].bottom = -1;
|
|
|
|
// Set up for planar banking:
|
|
|
|
ppdev->pfnPlanarSwitchCode =
|
|
(PFN) (((BYTE*)pBankInfo) + pBankInfo->PlanarHCBankCodeOffset);
|
|
ppdev->pfnPlanarEnable =
|
|
(PFN) (((BYTE*)pBankInfo) + pBankInfo->PlanarHCEnableCodeOffset);
|
|
ppdev->pfnPlanarDisable =
|
|
(PFN) (((BYTE*)pBankInfo) + pBankInfo->PlanarHCDisableCodeOffset);
|
|
|
|
ppdev->lPlanarNextScan = lDelta;
|
|
ppdev->vbtPlanarType = pBankInfo->PlanarHCBankingType;
|
|
|
|
// Set up to call the appropriate banking control routines
|
|
|
|
switch(ppdev->vbtPlanarType)
|
|
{
|
|
case VideoBanked1RW:
|
|
ppdev->pfnPlanarControl = vPlanar1Window;
|
|
ppdev->pfnPlanarControl2 = vPlanar2Window1RW;
|
|
break;
|
|
|
|
case VideoBanked1R1W:
|
|
ppdev->pfnPlanarControl = vPlanar1Window;
|
|
ppdev->pfnPlanarControl2 = vPlanar2Window;
|
|
break;
|
|
|
|
case VideoBanked2RW:
|
|
ppdev->pfnPlanarControl = vPlanar1Window2RW;
|
|
ppdev->pfnPlanarControl2 = vPlanar2Window2RW;
|
|
|
|
// Offset from one bank index to next to make two 32k banks
|
|
// appear to be one seamless 64k bank:
|
|
|
|
ppdev->ulPlanar2RWSkip = BANK_SIZE_2RW_WINDOW / cjGranularity;
|
|
break;
|
|
|
|
default:
|
|
RIP("Bad BankingType");
|
|
return(FALSE);
|
|
}
|
|
|
|
lTotalBanks = (cjBitmapSize + cjGranularity - 1) / cjGranularity;
|
|
lTotalScans = cjBitmapSize / lDelta;
|
|
|
|
ppdev->pbiPlanarInfo = (PBANK_INFO) EngAllocMem(FL_ZERO_MEMORY,
|
|
lTotalBanks * sizeof(BANK_INFO), ALLOC_TAG);
|
|
if (ppdev->pbiPlanarInfo == NULL)
|
|
{
|
|
DISPDBG((0, "VGA64K: Couldn't get memory for bank info"));
|
|
return(FALSE);
|
|
}
|
|
|
|
ppdev->pjJustifyTopPlanar = (BYTE*) EngAllocMem(0, lTotalScans, ALLOC_TAG);
|
|
if (ppdev->pjJustifyTopPlanar == NULL)
|
|
{
|
|
DISPDBG((0, "VGA64K: Couldn't get memory for JustifyTopBank table"));
|
|
return(FALSE);
|
|
}
|
|
|
|
// For 2 RW windows, windows are assumed to be 32k in size, otherwise
|
|
// assumed to be 64k:
|
|
|
|
if (pBankInfo->BankingType == VideoBanked2RW)
|
|
cjBankSize = BANK_SIZE_2RW_WINDOW;
|
|
else
|
|
cjBankSize = BANK_SIZE_1_WINDOW;
|
|
|
|
// if ((cjGranularity + lDelta) >= cjBankSize &&
|
|
// (cjGranularity % lDelta) != 0)
|
|
// {
|
|
// // Oh no, we've got broken rasters (where a scan line crosses
|
|
// // a bank boundary):
|
|
//
|
|
// DISPDBG((0, "Can't handle broken planar rasters"));
|
|
//
|
|
// ppdev->fl &= ~DRIVER_PLANAR_CAPABLE;// !!! Temporary, until we handle
|
|
// return(TRUE); // broken rasters in planar copy
|
|
// }
|
|
// else
|
|
{
|
|
// We now fill in the scan-to-bank look-up and bank tables:
|
|
|
|
LONG iScan = 0;
|
|
ULONG iBank = 0;
|
|
ULONG cjScan = 0;
|
|
ULONG cjNextBank = cjGranularity;
|
|
ULONG cjEndOfBank = cjBankSize;
|
|
PBANK_INFO pbiWorking = ppdev->pbiPlanarInfo;
|
|
|
|
while (TRUE)
|
|
{
|
|
pbiWorking->ulBankOffset = cjNextBank - cjGranularity;
|
|
|
|
// There are no broken rasters, so don't worry about left and right
|
|
// edges:
|
|
|
|
pbiWorking->rclBankBounds.left = LONG_MIN + 1; // +1 to avoid
|
|
// compiler warn
|
|
pbiWorking->rclBankBounds.right = LONG_MAX;
|
|
pbiWorking->rclBankBounds.top = iScan;
|
|
pbiWorking->rclBankBounds.bottom = iScan +
|
|
(cjEndOfBank - cjScan + lDelta - 1) / lDelta;
|
|
// this rounds up to handle broken rasters that are off the
|
|
// right side of the visible bitmap
|
|
|
|
// We don't need any more banks if we can see to the end
|
|
// of the bitmap with the current bank:
|
|
|
|
if (cjScan + cjBankSize >= cjBitmapSize)
|
|
break;
|
|
|
|
while (cjScan < cjNextBank)
|
|
{
|
|
ppdev->pjJustifyTopPlanar[iScan++] = (BYTE) iBank;
|
|
cjScan += lDelta;
|
|
}
|
|
|
|
// Get ready for next bank:
|
|
|
|
cjNextBank += cjGranularity;
|
|
cjEndOfBank += cjGranularity;
|
|
pbiWorking++;
|
|
iBank++;
|
|
}
|
|
|
|
// Clean up the last scans:
|
|
|
|
ppdev->iLastPlanar = iBank;
|
|
pbiWorking->rclBankBounds.bottom = lTotalScans;
|
|
while (iScan < lTotalScans)
|
|
{
|
|
ppdev->pjJustifyTopPlanar[iScan++] = (BYTE) iBank;
|
|
}
|
|
|
|
// We've just computed the precise table for JustifyTop; we now
|
|
// compute the scan offset for determining JustifyBottom:
|
|
|
|
ASSERTVGA(cjBankSize >= cjGranularity,
|
|
"Device says granularity more than bank size?");
|
|
|
|
ppdev->ulPlanarBottomOffset = (cjBankSize - cjGranularity) / lDelta;
|
|
|
|
// ulPlanarBottomOffset must be less than the number of scans
|
|
// that fit entirely in any bank less the granularity size; if
|
|
// our width doesn't divide evenly into the granularity, we'll
|
|
// have to adjust the value to account for the first scan not
|
|
// starting at offset 0 in any bank:
|
|
|
|
if ((cjGranularity % lDelta) != 0 && ppdev->ulPlanarBottomOffset > 0)
|
|
ppdev->ulPlanarBottomOffset--;
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* bEnableBanking(ppdev)
|
|
*
|
|
* Set up banking for the current mode
|
|
* pdsurf and ppdev are the pointers to the current surface and device
|
|
* Relevant fields in the surface are set up for banking
|
|
\**************************************************************************/
|
|
|
|
BOOL bEnableBanking(PPDEV ppdev)
|
|
{
|
|
PVIDEO_BANK_SELECT pBankInfo;
|
|
UINT ReturnedDataLength;
|
|
VIDEO_BANK_SELECT TempBankInfo;
|
|
DWORD status;
|
|
|
|
// Make sure we've set to NULL any pointers to buffers that we allocate,
|
|
// so that we can free them in our error path:
|
|
|
|
ppdev->pBankInfo = NULL;
|
|
ppdev->pjJustifyTopBank = NULL;
|
|
ppdev->pbiBankInfo = NULL;
|
|
ppdev->pjJustifyTopPlanar = NULL;
|
|
ppdev->pbiPlanarInfo = NULL;
|
|
|
|
// Query the miniport for banking info for this mode.
|
|
//
|
|
// First, figure out how big a buffer we need for the banking info
|
|
// (returned in TempBankInfo->Size).
|
|
|
|
if (status = EngDeviceIoControl(ppdev->hDriver,
|
|
IOCTL_VIDEO_GET_BANK_SELECT_CODE,
|
|
NULL, // input buffer
|
|
0,
|
|
(LPVOID) &TempBankInfo, // output buffer
|
|
sizeof(VIDEO_BANK_SELECT),
|
|
&ReturnedDataLength))
|
|
{
|
|
// We expect this call to fail, because we didn't allow any room
|
|
// for the code; we just want to get the required output buffer
|
|
// size. Make sure we got the expected error, ERROR_MORE_DATA.
|
|
}
|
|
|
|
// Now, allocate a buffer of the required size and get the banking info.
|
|
|
|
pBankInfo = (PVIDEO_BANK_SELECT) EngAllocMem(FL_ZERO_MEMORY,
|
|
TempBankInfo.Size, ALLOC_TAG);
|
|
if (pBankInfo == NULL)
|
|
{
|
|
DISPDBG((0, "VGA64K: Initialization error-couldn't get memory for bank info"));
|
|
goto error;
|
|
}
|
|
|
|
// Remember it so we can free it later:
|
|
|
|
ppdev->pBankInfo = pBankInfo;
|
|
|
|
if (EngDeviceIoControl(ppdev->hDriver,
|
|
IOCTL_VIDEO_GET_BANK_SELECT_CODE,
|
|
NULL,
|
|
0,
|
|
(LPVOID) pBankInfo,
|
|
TempBankInfo.Size,
|
|
&ReturnedDataLength))
|
|
{
|
|
RIP("Initialization error-GetBankSelectCode, second call");
|
|
goto error;
|
|
}
|
|
|
|
// Set up for banking:
|
|
|
|
ppdev->ulBitmapSize = pBankInfo->BitmapSize;
|
|
|
|
if (!bInitializeNonPlanar(ppdev, pBankInfo))
|
|
goto error;
|
|
|
|
if (pBankInfo->BankingFlags & PLANAR_HC)
|
|
{
|
|
ppdev->fl |= DRIVER_PLANAR_CAPABLE;
|
|
if (!bInitializePlanar(ppdev, pBankInfo))
|
|
goto error;
|
|
}
|
|
|
|
// Map in scan line 0 for read & write, to put things in a known state:
|
|
|
|
ppdev->pfnBankControl(ppdev, 0, JustifyTop);
|
|
|
|
return(TRUE);
|
|
|
|
// Error path:
|
|
|
|
error:
|
|
vDisableBanking(ppdev);
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* vDisableBanking(ppdev)
|
|
*
|
|
* Disable banking for the current mode
|
|
\**************************************************************************/
|
|
|
|
VOID vDisableBanking(PPDEV ppdev)
|
|
{
|
|
EngFreeMem((LPVOID) ppdev->pBankInfo);
|
|
EngFreeMem((LPVOID) ppdev->pjJustifyTopBank);
|
|
EngFreeMem((LPVOID) ppdev->pbiBankInfo);
|
|
EngFreeMem((LPVOID) ppdev->pjJustifyTopPlanar);
|
|
EngFreeMem((LPVOID) ppdev->pbiPlanarInfo);
|
|
}
|
|
|
|
/******************************Private*Routine******************************\
|
|
* vBankErrorTrap
|
|
*
|
|
* Traps calls to bank control functions in non-banked modes
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vBankErrorTrap(PPDEV ppdev, ULONG lScan, BANK_JUST ulJustification)
|
|
{
|
|
DISPDBG((0,"Call to bank manager in unbanked mode"));
|
|
}
|
|
|
|
/******************************Private*Routine******************************\
|
|
* vBank1Window
|
|
*
|
|
* Maps in a single R/W window that allows access to lScan. Applies to both
|
|
* 1 RW window and 1R1W window banking schemes.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vBank1Window(PPDEV ppdev, ULONG lScan, BANK_JUST ulJustification)
|
|
{
|
|
ULONG ulBank;
|
|
PBANK_INFO pbiWorking;
|
|
volatile ULONG ulBank0;
|
|
volatile PFN pBankFn;
|
|
BANK_POSITION BankPosition;
|
|
ULONG ulReturn;
|
|
|
|
// ASM routines that call this may have STD in effect, but the C compiler
|
|
// assumes CLD
|
|
|
|
_asm pushfd
|
|
_asm cld
|
|
|
|
// Set the clip rect for this bank; if it's set to -1, that indicates that
|
|
// a double-window set-up is currently active, so invalidate double-window
|
|
// clip rects and display memory pointers (when double-window is active,
|
|
// single-window is inactive, and vice-versa; a full bank set-up has to be
|
|
// performed to switch between the two)
|
|
|
|
if (ppdev->rcl1WindowClip.bottom == -1)
|
|
{
|
|
if (ppdev->flBank & BANK_PLANAR)
|
|
{
|
|
ppdev->flBank &= ~BANK_PLANAR;
|
|
ppdev->pfnPlanarDisable();
|
|
}
|
|
|
|
ppdev->rcl2WindowClip[0].bottom = -1;
|
|
ppdev->rcl2WindowClip[1].bottom = -1;
|
|
ppdev->rcl1PlanarClip.bottom = -1;
|
|
ppdev->rcl2PlanarClip[0].bottom = -1;
|
|
ppdev->rcl2PlanarClip[1].bottom = -1;
|
|
}
|
|
|
|
ASSERTVGA(!(ppdev->flBank & BANK_PLANAR), "Shouldn't be in planar mode");
|
|
|
|
// Find the bank containing the scan line with the desired justification:
|
|
|
|
{
|
|
register LONG lSearchScan = lScan;
|
|
if (ulJustification == JustifyBottom)
|
|
{
|
|
lSearchScan -= ppdev->ulJustifyBottomOffset;
|
|
if (lSearchScan <= 0)
|
|
lSearchScan = 0;
|
|
}
|
|
|
|
ulBank = (ULONG) ppdev->pjJustifyTopBank[lSearchScan];
|
|
pbiWorking = &ppdev->pbiBankInfo[ulBank];
|
|
}
|
|
|
|
ASSERTVGA(pbiWorking->rclBankBounds.top <= (LONG)lScan &&
|
|
pbiWorking->rclBankBounds.bottom > (LONG)lScan,
|
|
"Oops, scan not in bank");
|
|
|
|
ppdev->rcl1WindowClip = pbiWorking->rclBankBounds;
|
|
|
|
// Shift the bitmap start address so that the desired bank aligns with
|
|
// the banking window. The source and destination are set only so 1 R/W
|
|
// aligned blits will work without having to be specifically aware of
|
|
// the adapter type (some of the same code works with 1R/1W adapters too).
|
|
|
|
ppdev->pvBitmapStart = (PVOID) (ppdev->pjScreen - pbiWorking->ulBankOffset);
|
|
ppdev->pvBitmapStart2Window[0] = ppdev->pvBitmapStart;
|
|
ppdev->pvBitmapStart2Window[1] = ppdev->pvBitmapStart;
|
|
|
|
ppdev->flBank &= ~BANK_BROKEN_RASTERS; // No broken rasters
|
|
|
|
// Map in the desired bank for both read and write
|
|
// This is so convoluted to avoid problems with wiping out registers C
|
|
// thinks it's still using; the values are tranferred to volatiles, and
|
|
// then to registers
|
|
|
|
ulBank0 = ulBank;
|
|
|
|
if (ppdev->BankIoctlSupported) {
|
|
|
|
static ULONG ulBankOld = -1;
|
|
|
|
if (ulBankOld != ulBank0) {
|
|
|
|
BankPosition.ReadBankPosition = ulBank0;
|
|
BankPosition.WriteBankPosition = ulBank0;
|
|
|
|
ulBankOld = ulBank0;
|
|
|
|
EngDeviceIoControl(ppdev->hDriver,
|
|
IOCTL_VIDEO_SET_BANK_POSITION,
|
|
&BankPosition,
|
|
sizeof(BANK_POSITION),
|
|
NULL,
|
|
0,
|
|
&ulReturn);
|
|
}
|
|
|
|
} else {
|
|
|
|
pBankFn = ppdev->pfnBankSwitchCode;
|
|
|
|
_asm mov eax,ulBank0;
|
|
_asm mov edx,eax;
|
|
_asm call pBankFn; // actually switch the banks
|
|
}
|
|
|
|
_asm popfd
|
|
}
|
|
|
|
/******************************Private*Routine******************************\
|
|
* vBank1Window2RW
|
|
*
|
|
* Maps in two 32K RW windows so that they form a single 64K R/W window that
|
|
* allows access to lScan. Applies only to 2 RW window schemes.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vBank1Window2RW(PPDEV ppdev, ULONG lScan, BANK_JUST ulJustification)
|
|
{
|
|
ULONG ulBank0;
|
|
ULONG ulBank1;
|
|
volatile PFN pBankFn;
|
|
|
|
// ASM routines that call this may have STD in effect, but the C compiler
|
|
// assumes CLD
|
|
|
|
_asm pushfd
|
|
_asm cld
|
|
|
|
// Set the clip rect for this bank; if it's set to -1, that indicates that
|
|
// a double-window set-up is currently active, so invalidate double-window
|
|
// clip rects and display memory pointers (when double-window is active,
|
|
// single-window is inactive, and vice-versa; a full bank set-up has to be
|
|
// performed to switch between the two)
|
|
|
|
if (ppdev->rcl1WindowClip.bottom == -1)
|
|
{
|
|
if (ppdev->flBank & BANK_PLANAR)
|
|
{
|
|
ppdev->flBank &= ~BANK_PLANAR;
|
|
ppdev->pfnPlanarDisable();
|
|
}
|
|
|
|
ppdev->rcl2WindowClip[0].bottom = -1;
|
|
ppdev->rcl2WindowClip[1].bottom = -1;
|
|
ppdev->rcl1PlanarClip.bottom = -1;
|
|
ppdev->rcl2PlanarClip[0].bottom = -1;
|
|
ppdev->rcl2PlanarClip[1].bottom = -1;
|
|
}
|
|
|
|
ASSERTVGA(!(ppdev->flBank & BANK_PLANAR), "Shouldn't be in planar mode");
|
|
|
|
// Find the bank containing the scan line with the desired justification:
|
|
|
|
if (ulJustification == JustifyTop)
|
|
{
|
|
ulBank0 = ppdev->pjJustifyTopBank[lScan];
|
|
ulBank1 = ulBank0 + ppdev->ulBank2RWSkip;
|
|
if (ulBank1 >= ppdev->iLastBank)
|
|
{
|
|
ulBank1 = ppdev->iLastBank;
|
|
ulBank0 = ulBank1 - ppdev->ulBank2RWSkip;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lScan -= ppdev->ulJustifyBottomOffset;
|
|
if ((LONG)lScan <= 0)
|
|
lScan = 0;
|
|
|
|
ulBank1 = ppdev->pjJustifyTopBank[lScan];
|
|
ulBank0 = ulBank1 - ppdev->ulBank2RWSkip;
|
|
if ((LONG) ulBank0 < 0)
|
|
{
|
|
ulBank0 = 0;
|
|
ulBank1 = ppdev->ulBank2RWSkip;
|
|
}
|
|
}
|
|
|
|
ppdev->rcl1WindowClip.left = ppdev->pbiBankInfo[ulBank0].rclBankBounds.left;
|
|
ppdev->rcl1WindowClip.top = ppdev->pbiBankInfo[ulBank0].rclBankBounds.top;
|
|
ppdev->rcl1WindowClip.bottom = ppdev->pbiBankInfo[ulBank1].rclBankBounds.bottom;
|
|
ppdev->rcl1WindowClip.right = ppdev->pbiBankInfo[ulBank1].rclBankBounds.right;
|
|
|
|
// Shift the bitmap start address so that the desired bank aligns with
|
|
// the banking window. The source and destination are set only so 1 R/W
|
|
// aligned blits will work without having to be specifically aware of
|
|
// the adapter type (some of the same code works with 1R/1W adapters too).
|
|
|
|
ppdev->pvBitmapStart = (PVOID) ((BYTE*)ppdev->pjScreen
|
|
- ppdev->pbiBankInfo[ulBank0].ulBankOffset);
|
|
|
|
ppdev->pvBitmapStart2Window[0] = ppdev->pvBitmapStart;
|
|
ppdev->pvBitmapStart2Window[1] = ppdev->pvBitmapStart;
|
|
|
|
ppdev->flBank &= ~BANK_BROKEN_RASTERS; // No broken rasters
|
|
|
|
// Map in the desired bank for both read and write; this is accomplished
|
|
// by mapping in the desired 32K bank, followed by the next 32K bank.
|
|
// This is so convoluted to avoid problems with wiping out registers C
|
|
// thinks it's still using; the values are tranferred to volatiles, and
|
|
// then to registers
|
|
|
|
pBankFn = ppdev->pfnBankSwitchCode;
|
|
|
|
_asm mov eax,ulBank0;
|
|
_asm mov edx,ulBank1;
|
|
_asm call pBankFn; // actually switch the banks
|
|
|
|
_asm popfd;
|
|
}
|
|
|
|
/******************************Private*Routine******************************\
|
|
* vBank2Window
|
|
*
|
|
* Maps in one of two windows, either the source window (window 0) or the dest
|
|
* window (window 1), to allows access to lScan. Applies to 1R1W window
|
|
* banking scheme; should never be called for 1 RW window schemes, because
|
|
* there's only one window in that case.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vBank2Window(
|
|
PPDEV ppdev,
|
|
ULONG lScan,
|
|
BANK_JUST ulJustification,
|
|
ULONG ulWindowToMap)
|
|
{
|
|
ULONG ulBank;
|
|
PBANK_INFO pbiWorking;
|
|
volatile ULONG ulBank0;
|
|
volatile ULONG ulBank1;
|
|
volatile PFN pBankFn;
|
|
|
|
// ASM routines that call this may have STD in effect, but the C compiler
|
|
// assumes CLD
|
|
|
|
_asm pushfd
|
|
_asm cld
|
|
|
|
// Find the bank containing the scan line with the desired justification:
|
|
|
|
if (ulJustification == JustifyBottom)
|
|
{
|
|
lScan -= ppdev->ulJustifyBottomOffset;
|
|
if ((LONG)lScan <= 0)
|
|
lScan = 0;
|
|
}
|
|
|
|
ulBank = (ULONG) ppdev->pjJustifyTopBank[lScan];
|
|
pbiWorking = &ppdev->pbiBankInfo[ulBank];
|
|
|
|
// Set the clip rect for this bank; if it's set to -1, that indicates that
|
|
// a single-window set-up is currently active, so invalidate single-window
|
|
// clip rects and display memory pointers (when double-window is active,
|
|
// single-window is inactive, and vice-versa; a full bank set-up has to be
|
|
// performed to switch between the two)
|
|
|
|
if (ppdev->rcl2WindowClip[ulWindowToMap].bottom == -1)
|
|
{
|
|
ULONG ulOtherWindow = ulWindowToMap ^ 1;
|
|
|
|
if (ppdev->flBank & BANK_PLANAR)
|
|
{
|
|
ppdev->flBank &= ~BANK_PLANAR;
|
|
ppdev->pfnPlanarDisable();
|
|
}
|
|
|
|
ppdev->rcl1WindowClip.bottom = -1;
|
|
ppdev->rcl1PlanarClip.bottom = -1;
|
|
ppdev->rcl2PlanarClip[0].bottom = -1;
|
|
ppdev->rcl2PlanarClip[1].bottom = -1;
|
|
|
|
// Neither of the 2 window windows was active, so we have to set up the
|
|
// variables for the other bank (the one other than the one we were
|
|
// called to set) as well, to make it valid. The other bank is set to
|
|
// the same state as the bank we were called to set
|
|
|
|
ppdev->rcl2WindowClip[ulOtherWindow] = pbiWorking->rclBankBounds;
|
|
ppdev->ulWindowBank[ulOtherWindow] = ulBank;
|
|
ppdev->pvBitmapStart2Window[ulOtherWindow] =
|
|
(PVOID) ((BYTE*)ppdev->pjScreen - pbiWorking->ulBankOffset);
|
|
}
|
|
|
|
ASSERTVGA(!(ppdev->flBank & BANK_PLANAR), "Shouldn't be in planar mode");
|
|
|
|
ppdev->rcl2WindowClip[ulWindowToMap] = pbiWorking->rclBankBounds;
|
|
|
|
// Shift the bitmap start address so that the desired bank aligns with the
|
|
// banking window
|
|
|
|
ppdev->pvBitmapStart2Window[ulWindowToMap] =
|
|
(PVOID) ((UCHAR *)ppdev->pjScreen - pbiWorking->ulBankOffset);
|
|
|
|
// Map in the desired bank; also map in the other bank to whatever its
|
|
// current state is
|
|
|
|
ppdev->ulWindowBank[ulWindowToMap] = ulBank;
|
|
|
|
ppdev->flBank &= ~BANK_BROKEN_RASTERS; // No broken rasters
|
|
|
|
// Set both banks at once, because we may have just initialized the other
|
|
// bank, and because this way the bank switch code doesn't have to do a
|
|
// read before write to obtain the state of the other bank.
|
|
// This is so convoluted to avoid problems with wiping out registers C
|
|
// thinks it's still using; the values are tranferred to volatiles, and
|
|
// then to registers
|
|
|
|
|
|
ulBank0 = ppdev->ulWindowBank[0];
|
|
ulBank1 = ppdev->ulWindowBank[1];
|
|
pBankFn = ppdev->pfnBankSwitchCode;
|
|
|
|
_asm mov eax,ulBank0;
|
|
_asm mov edx,ulBank1;
|
|
_asm call pBankFn; // actually switch the banks
|
|
|
|
_asm popfd;
|
|
}
|
|
|
|
/******************************Private*Routine******************************\
|
|
* vBank2Window1RW
|
|
*
|
|
* Maps in the one window in 1R/W case. Does exactly the same thing as the
|
|
* one window case, because there's only one window, but has to be a separate
|
|
* entry point because of the extra parameter (because we're using STDCALL).
|
|
\**************************************************************************/
|
|
|
|
VOID vBank2Window1RW(PPDEV ppdev, ULONG lScan,
|
|
BANK_JUST ulJustification, ULONG ulWindowToMap)
|
|
{
|
|
vBank1Window(ppdev, lScan, ulJustification);
|
|
}
|
|
|
|
/******************************Private*Routine******************************\
|
|
* vBank2Window2RW
|
|
*
|
|
* Maps in one of two windows, either the source window (window 0) or the dest
|
|
* window (window 1), to allows access to lScan. Applies to 2RW window
|
|
* banking scheme; should never be called for 1 RW window schemes, because
|
|
* there's only one window in that case.
|
|
\**************************************************************************/
|
|
|
|
VOID vBank2Window2RW(
|
|
PPDEV ppdev,
|
|
ULONG lScan,
|
|
BANK_JUST ulJustification,
|
|
ULONG ulWindowToMap)
|
|
{
|
|
ULONG ulBank;
|
|
PBANK_INFO pbiWorking;
|
|
volatile ULONG ulBank0;
|
|
volatile ULONG ulBank1;
|
|
volatile PFN pBankFn;
|
|
|
|
// ASM routines that call this may have STD in effect, but the C compiler
|
|
// assumes CLD
|
|
|
|
_asm pushfd
|
|
_asm cld
|
|
|
|
// Find the bank containing the scan line with the desired justification:
|
|
|
|
if (ulJustification == JustifyBottom)
|
|
{
|
|
lScan -= ppdev->ulJustifyBottomOffset;
|
|
if ((LONG)lScan <= 0)
|
|
lScan = 0;
|
|
}
|
|
|
|
ulBank = (ULONG) ppdev->pjJustifyTopBank[lScan];
|
|
pbiWorking = &ppdev->pbiBankInfo[ulBank];
|
|
|
|
// Set the clip rect for this bank; if it's set to -1, that indicates that
|
|
// a single-window set-up is currently active, so invalidate single-window
|
|
// clip rects and display memory pointers (when double-window is active,
|
|
// single-window is inactive, and vice-versa; a full bank set-up has to be
|
|
// performed to switch between the two)
|
|
|
|
if (ppdev->rcl2WindowClip[ulWindowToMap].bottom == -1)
|
|
{
|
|
if (ppdev->flBank & BANK_PLANAR)
|
|
{
|
|
ppdev->flBank &= ~BANK_PLANAR;
|
|
ppdev->pfnPlanarDisable();
|
|
}
|
|
|
|
ppdev->rcl1WindowClip.bottom = -1;
|
|
ppdev->rcl1PlanarClip.bottom = -1;
|
|
ppdev->rcl2PlanarClip[0].bottom = -1;
|
|
ppdev->rcl2PlanarClip[1].bottom = -1;
|
|
|
|
// Neither of the 2 window windows was active, so we have to set up the
|
|
// variables for the other bank (the one other than the one we were
|
|
// called to set) as well, to make it valid. The other bank is set to
|
|
// the same state as the bank we were called to set
|
|
|
|
ppdev->rcl2WindowClip[ulWindowToMap^1] = pbiWorking->rclBankBounds;
|
|
if (ulWindowToMap == 1)
|
|
{
|
|
ppdev->pvBitmapStart2Window[0] =
|
|
(PVOID) ((BYTE*)ppdev->pjScreen - pbiWorking->ulBankOffset);
|
|
}
|
|
else
|
|
{
|
|
ppdev->pvBitmapStart2Window[1] =
|
|
(PVOID) ((UCHAR *)ppdev->pjScreen - pbiWorking->ulBankOffset +
|
|
BANK_SIZE_2RW_WINDOW);
|
|
}
|
|
ppdev->ulWindowBank[ulWindowToMap^1] = ulBank;
|
|
}
|
|
|
|
ASSERTVGA(!(ppdev->flBank & BANK_PLANAR), "Shouldn't be in planar mode");
|
|
|
|
ppdev->rcl2WindowClip[ulWindowToMap] = pbiWorking->rclBankBounds;
|
|
|
|
// Shift the bitmap start address so that the desired bank aligns with the
|
|
// banking window
|
|
|
|
if (ulWindowToMap == 0)
|
|
{
|
|
ppdev->pvBitmapStart2Window[0] =
|
|
(PVOID) ((UCHAR *)ppdev->pjScreen - pbiWorking->ulBankOffset);
|
|
}
|
|
else
|
|
{
|
|
ppdev->pvBitmapStart2Window[1] =
|
|
(PVOID) ((UCHAR *)ppdev->pjScreen - pbiWorking->ulBankOffset +
|
|
BANK_SIZE_2RW_WINDOW);
|
|
}
|
|
|
|
ppdev->flBank &= ~BANK_BROKEN_RASTERS; // No broken rasters
|
|
|
|
// Map in the desired bank; also map in the other bank to whatever its
|
|
// current state is
|
|
|
|
ppdev->ulWindowBank[ulWindowToMap] = ulBank;
|
|
|
|
// Set both banks at once, because we may have just initialized the other
|
|
// bank, and because this way the bank switch code doesn't have to do a
|
|
// read before write to obtain the state of the other bank.
|
|
// This is so convoluted to avoid problems with wiping out registers C
|
|
// thinks it's still using; the values are tranferred to volatiles, and
|
|
// then to registers
|
|
|
|
ulBank0 = ppdev->ulWindowBank[0];
|
|
ulBank1 = ppdev->ulWindowBank[1];
|
|
pBankFn = ppdev->pfnBankSwitchCode;
|
|
_asm mov eax,ulBank0;
|
|
_asm mov edx,ulBank1;
|
|
_asm call pBankFn; // actually switch the banks
|
|
|
|
_asm popfd;
|
|
}
|
|
|
|
/******************************Private*Routine******************************\
|
|
* vPlanar1Window
|
|
*
|
|
* Maps in a single R/W window that allows access to lScan. Applies to both
|
|
* 1 RW window and 1R1W window banking schemes.
|
|
\**************************************************************************/
|
|
|
|
VOID vPlanar1Window(PPDEV ppdev, ULONG lScan, BANK_JUST ulJustification)
|
|
{
|
|
ULONG ulBank;
|
|
PBANK_INFO pbiWorking;
|
|
volatile ULONG ulBank0;
|
|
volatile PFN pBankFn;
|
|
|
|
// ASM routines that call this may have STD in effect, but the C compiler
|
|
// assumes CLD
|
|
|
|
_asm pushfd
|
|
_asm cld
|
|
|
|
// Set the clip rect for this bank; if it's set to -1, that indicates that
|
|
// a double-window set-up is currently active, so invalidate double-window
|
|
// clip rects and display memory pointers (when double-window is active,
|
|
// single-window is inactive, and vice-versa; a full bank set-up has to be
|
|
// performed to switch between the two)
|
|
|
|
if (ppdev->rcl1PlanarClip.bottom == -1)
|
|
{
|
|
if (!(ppdev->flBank & BANK_PLANAR))
|
|
{
|
|
ppdev->flBank |= BANK_PLANAR;
|
|
ppdev->pfnPlanarEnable();
|
|
}
|
|
|
|
ppdev->rcl1WindowClip.bottom = -1;
|
|
ppdev->rcl2WindowClip[0].bottom = -1;
|
|
ppdev->rcl2WindowClip[1].bottom = -1;
|
|
ppdev->rcl2PlanarClip[0].bottom = -1;
|
|
ppdev->rcl2PlanarClip[1].bottom = -1;
|
|
}
|
|
|
|
ASSERTVGA(ppdev->flBank & BANK_PLANAR, "Should be in planar mode");
|
|
|
|
// Find the bank containing the scan line with the desired justification:
|
|
|
|
if (ulJustification == JustifyBottom)
|
|
{
|
|
lScan -= ppdev->ulPlanarBottomOffset;
|
|
if ((LONG)lScan <= 0)
|
|
lScan = 0;
|
|
}
|
|
|
|
ulBank = (ULONG) ppdev->pjJustifyTopPlanar[lScan];
|
|
pbiWorking = &ppdev->pbiPlanarInfo[ulBank];
|
|
|
|
ppdev->rcl1PlanarClip = pbiWorking->rclBankBounds;
|
|
|
|
// Shift the bitmap start address so that the desired bank aligns with
|
|
// the banking window. The source and destination are set only so 1 R/W
|
|
// aligned blits will work without having to be specifically aware of
|
|
// the adapter type (some of the same code works with 1R/1W adapters too).
|
|
|
|
ppdev->pvBitmapStart = (PVOID) (ppdev->pjScreen - pbiWorking->ulBankOffset);
|
|
ppdev->pvBitmapStart2Window[0] = ppdev->pvBitmapStart;
|
|
ppdev->pvBitmapStart2Window[1] = ppdev->pvBitmapStart;
|
|
|
|
ppdev->flBank &= ~BANK_BROKEN_RASTERS; // No broken rasters
|
|
|
|
// Map in the desired bank for both read and write
|
|
// This is so convoluted to avoid problems with wiping out registers C
|
|
// thinks it's still using; the values are tranferred to volatiles, and
|
|
// then to registers
|
|
|
|
ulBank0 = ulBank;
|
|
pBankFn = ppdev->pfnPlanarSwitchCode;
|
|
|
|
_asm mov eax,ulBank0;
|
|
_asm mov edx,eax;
|
|
_asm call pBankFn; // actually switch the banks
|
|
|
|
_asm popfd
|
|
}
|
|
|
|
/******************************Private*Routine******************************\
|
|
* vPlanar1Window2RW
|
|
*
|
|
* Maps in two 32K RW windows so that they form a single 64K R/W window that
|
|
* allows access to lScan. Applies only to 2 RW window schemes.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vPlanar1Window2RW(PPDEV ppdev, ULONG lScan, BANK_JUST ulJustification)
|
|
{
|
|
ULONG ulBank0;
|
|
ULONG ulBank1;
|
|
volatile PFN pBankFn;
|
|
|
|
// ASM routines that call this may have STD in effect, but the C compiler
|
|
// assumes CLD
|
|
|
|
_asm pushfd
|
|
_asm cld
|
|
|
|
// Set the clip rect for this bank; if it's set to -1, that indicates that
|
|
// a double-window set-up is currently active, so invalidate double-window
|
|
// clip rects and display memory pointers (when double-window is active,
|
|
// single-window is inactive, and vice-versa; a full bank set-up has to be
|
|
// performed to switch between the two)
|
|
|
|
|
|
if (ppdev->rcl1PlanarClip.bottom == -1)
|
|
{
|
|
if (!(ppdev->flBank & BANK_PLANAR))
|
|
{
|
|
ppdev->flBank |= BANK_PLANAR;
|
|
ppdev->pfnPlanarEnable();
|
|
}
|
|
|
|
ppdev->rcl1WindowClip.bottom = -1;
|
|
ppdev->rcl2WindowClip[0].bottom = -1;
|
|
ppdev->rcl2WindowClip[1].bottom = -1;
|
|
ppdev->rcl2PlanarClip[0].bottom = -1;
|
|
ppdev->rcl2PlanarClip[1].bottom = -1;
|
|
}
|
|
|
|
ASSERTVGA(ppdev->flBank & BANK_PLANAR, "Should be in planar mode");
|
|
|
|
// Find the bank containing the scan line with the desired justification:
|
|
|
|
if (ulJustification == JustifyTop)
|
|
{
|
|
ulBank0 = ppdev->pjJustifyTopPlanar[lScan];
|
|
ulBank1 = ulBank0 + ppdev->ulPlanar2RWSkip;
|
|
if (ulBank1 >= ppdev->iLastPlanar)
|
|
ulBank1 = ppdev->iLastPlanar;
|
|
}
|
|
else
|
|
{
|
|
lScan -= ppdev->ulPlanarBottomOffset;
|
|
if ((LONG)lScan <= 0)
|
|
lScan = 0;
|
|
|
|
ulBank1 = ppdev->pjJustifyTopPlanar[lScan];
|
|
ulBank0 = ulBank1 - ppdev->ulPlanar2RWSkip;
|
|
if ((LONG) ulBank0 < 0)
|
|
ulBank0 = 0;
|
|
}
|
|
|
|
ppdev->rcl1PlanarClip.left = ppdev->pbiPlanarInfo[ulBank0].rclBankBounds.left;
|
|
ppdev->rcl1PlanarClip.top = ppdev->pbiPlanarInfo[ulBank0].rclBankBounds.top;
|
|
ppdev->rcl1PlanarClip.bottom = ppdev->pbiPlanarInfo[ulBank1].rclBankBounds.bottom;
|
|
ppdev->rcl1PlanarClip.right = ppdev->pbiPlanarInfo[ulBank1].rclBankBounds.right;
|
|
|
|
// Shift the bitmap start address so that the desired bank aligns with
|
|
// the banking window. The source and destination are set only so 1 R/W
|
|
// aligned blits will work without having to be specifically aware of
|
|
// the adapter type (some of the same code works with 1R/1W adapters too).
|
|
|
|
ppdev->pvBitmapStart = (PVOID) ((BYTE*)ppdev->pjScreen
|
|
- ppdev->pbiPlanarInfo[ulBank0].ulBankOffset);
|
|
|
|
ppdev->pvBitmapStart2Window[0] = ppdev->pvBitmapStart;
|
|
ppdev->pvBitmapStart2Window[1] = ppdev->pvBitmapStart;
|
|
|
|
ppdev->flBank &= ~BANK_BROKEN_RASTERS; // No broken rasters
|
|
|
|
// Map in the desired bank for both read and write; this is accomplished
|
|
// by mapping in the desired 32K bank, followed by the next 32K bank.
|
|
// This is so convoluted to avoid problems with wiping out registers C
|
|
// thinks it's still using; the values are tranferred to volatiles, and
|
|
// then to registers
|
|
|
|
pBankFn = ppdev->pfnPlanarSwitchCode;
|
|
|
|
_asm mov eax,ulBank0;
|
|
_asm mov edx,ulBank1;
|
|
_asm call pBankFn; // actually switch the banks
|
|
|
|
_asm popfd;
|
|
}
|
|
|
|
/******************************Private*Routine******************************\
|
|
* vPlanar2Window
|
|
*
|
|
* Maps in one of two windows, either the source window (window 0) or the dest
|
|
* window (window 1), to allows access to lScan. Applies to 1R1W window
|
|
* banking scheme; should never be called for 1 RW window schemes, because
|
|
* there's only one window in that case.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vPlanar2Window(
|
|
PPDEV ppdev,
|
|
ULONG lScan,
|
|
BANK_JUST ulJustification,
|
|
ULONG ulWindowToMap)
|
|
{
|
|
ULONG ulBank;
|
|
PBANK_INFO pbiWorking;
|
|
volatile ULONG ulBank0;
|
|
volatile ULONG ulBank1;
|
|
volatile PFN pBankFn;
|
|
|
|
// ASM routines that call this may have STD in effect, but the C compiler
|
|
// assumes CLD
|
|
|
|
_asm pushfd
|
|
_asm cld
|
|
|
|
// Find the bank containing the scan line with the desired justification:
|
|
|
|
if (ulJustification == JustifyBottom)
|
|
{
|
|
lScan -= ppdev->ulPlanarBottomOffset;
|
|
if ((LONG)lScan <= 0)
|
|
lScan = 0;
|
|
}
|
|
|
|
ulBank = (ULONG) ppdev->pjJustifyTopPlanar[lScan];
|
|
pbiWorking = &ppdev->pbiPlanarInfo[ulBank];
|
|
|
|
// Set the clip rect for this bank; if it's set to -1, that indicates that
|
|
// a single-window set-up is currently active, so invalidate single-window
|
|
// clip rects and display memory pointers (when double-window is active,
|
|
// single-window is inactive, and vice-versa; a full bank set-up has to be
|
|
// performed to switch between the two)
|
|
|
|
if (ppdev->rcl2PlanarClip[ulWindowToMap].bottom == -1)
|
|
{
|
|
ULONG ulOtherWindow = ulWindowToMap ^ 1;
|
|
|
|
if (!(ppdev->flBank & BANK_PLANAR))
|
|
{
|
|
ppdev->flBank |= BANK_PLANAR;
|
|
ppdev->pfnPlanarEnable();
|
|
}
|
|
|
|
ppdev->rcl1WindowClip.bottom = -1;
|
|
ppdev->rcl2WindowClip[0].bottom = -1;
|
|
ppdev->rcl2WindowClip[1].bottom = -1;
|
|
ppdev->rcl1PlanarClip.bottom = -1;
|
|
|
|
// Neither of the 2 window windows was active, so we have to set up the
|
|
// variables for the other bank (the one other than the one we were
|
|
// called to set) as well, to make it valid. The other bank is set to
|
|
// the same state as the bank we were called to set
|
|
|
|
ppdev->rcl2PlanarClip[ulOtherWindow] = pbiWorking->rclBankBounds;
|
|
ppdev->ulWindowBank[ulOtherWindow] = ulBank;
|
|
ppdev->pvBitmapStart2Window[ulOtherWindow] =
|
|
(PVOID) ((BYTE*)ppdev->pjScreen - pbiWorking->ulBankOffset);
|
|
}
|
|
|
|
ASSERTVGA(ppdev->flBank & BANK_PLANAR, "Should be in planar mode");
|
|
|
|
ppdev->rcl2PlanarClip[ulWindowToMap] = pbiWorking->rclBankBounds;
|
|
|
|
// Shift the bitmap start address so that the desired bank aligns with the
|
|
// banking window
|
|
|
|
ppdev->pvBitmapStart2Window[ulWindowToMap] =
|
|
(PVOID) ((UCHAR *)ppdev->pjScreen - pbiWorking->ulBankOffset);
|
|
|
|
// Map in the desired bank; also map in the other bank to whatever its
|
|
// current state is
|
|
|
|
ppdev->ulWindowBank[ulWindowToMap] = ulBank;
|
|
|
|
ppdev->flBank &= ~BANK_BROKEN_RASTERS; // No broken rasters
|
|
|
|
// Set both banks at once, because we may have just initialized the other
|
|
// bank, and because this way the bank switch code doesn't have to do a
|
|
// read before write to obtain the state of the other bank.
|
|
// This is so convoluted to avoid problems with wiping out registers C
|
|
// thinks it's still using; the values are tranferred to volatiles, and
|
|
// then to registers
|
|
|
|
|
|
ulBank0 = ppdev->ulWindowBank[0];
|
|
ulBank1 = ppdev->ulWindowBank[1];
|
|
pBankFn = ppdev->pfnPlanarSwitchCode;
|
|
|
|
_asm mov eax,ulBank0;
|
|
_asm mov edx,ulBank1;
|
|
_asm call pBankFn; // actually switch the banks
|
|
|
|
_asm popfd;
|
|
}
|
|
|
|
/******************************Private*Routine******************************\
|
|
* vPlanar2Window1RW
|
|
*
|
|
* Maps in the one window in 1R/W case. Does exactly the same thing as the
|
|
* one window case, because there's only one window, but has to be a separate
|
|
* entry point because of the extra parameter (because we're using STDCALL).
|
|
\**************************************************************************/
|
|
|
|
VOID vPlanar2Window1RW(PPDEV ppdev, ULONG lScan,
|
|
BANK_JUST ulJustification, ULONG ulWindowToMap)
|
|
{
|
|
vPlanar1Window(ppdev, lScan, ulJustification);
|
|
}
|
|
|
|
/******************************Private*Routine******************************\
|
|
* vPlanar2Window2RW
|
|
*
|
|
* Maps in one of two windows, either the source window (window 0) or the dest
|
|
* window (window 1), to allows access to lScan. Applies to 2RW window
|
|
* banking scheme; should never be called for 1 RW window schemes, because
|
|
* there's only one window in that case.
|
|
\**************************************************************************/
|
|
|
|
VOID vPlanar2Window2RW(
|
|
PPDEV ppdev,
|
|
ULONG lScan,
|
|
BANK_JUST ulJustification,
|
|
ULONG ulWindowToMap)
|
|
{
|
|
ULONG ulBank;
|
|
PBANK_INFO pbiWorking;
|
|
volatile ULONG ulBank0;
|
|
volatile ULONG ulBank1;
|
|
volatile PFN pBankFn;
|
|
|
|
// ASM routines that call this may have STD in effect, but the C compiler
|
|
// assumes CLD
|
|
|
|
_asm pushfd
|
|
_asm cld
|
|
|
|
// Find the bank containing the scan line with the desired justification:
|
|
|
|
if (ulJustification == JustifyBottom)
|
|
{
|
|
lScan -= ppdev->ulPlanarBottomOffset;
|
|
if ((LONG)lScan <= 0)
|
|
lScan = 0;
|
|
}
|
|
|
|
ulBank = (ULONG) ppdev->pjJustifyTopPlanar[lScan];
|
|
pbiWorking = &ppdev->pbiPlanarInfo[ulBank];
|
|
|
|
// Set the clip rect for this bank; if it's set to -1, that indicates that
|
|
// a single-window set-up is currently active, so invalidate single-window
|
|
// clip rects and display memory pointers (when double-window is active,
|
|
// single-window is inactive, and vice-versa; a full bank set-up has to be
|
|
// performed to switch between the two)
|
|
|
|
if (ppdev->rcl2PlanarClip[ulWindowToMap].bottom == -1)
|
|
{
|
|
if (!(ppdev->flBank & BANK_PLANAR))
|
|
{
|
|
ppdev->flBank |= BANK_PLANAR;
|
|
ppdev->pfnPlanarEnable();
|
|
}
|
|
|
|
ppdev->rcl1WindowClip.bottom = -1;
|
|
ppdev->rcl2WindowClip[0].bottom = -1;
|
|
ppdev->rcl2WindowClip[1].bottom = -1;
|
|
ppdev->rcl1PlanarClip.bottom = -1;
|
|
|
|
// Neither of the 2 window windows was active, so we have to set up the
|
|
// variables for the other bank (the one other than the one we were
|
|
// called to set) as well, to make it valid. The other bank is set to
|
|
// the same state as the bank we were called to set
|
|
|
|
ppdev->rcl2PlanarClip[ulWindowToMap^1] = pbiWorking->rclBankBounds;
|
|
if (ulWindowToMap == 1)
|
|
{
|
|
ppdev->pvBitmapStart2Window[0] =
|
|
(PVOID) ((BYTE*)ppdev->pjScreen - pbiWorking->ulBankOffset);
|
|
}
|
|
else
|
|
{
|
|
ppdev->pvBitmapStart2Window[1] =
|
|
(PVOID) ((UCHAR *)ppdev->pjScreen - pbiWorking->ulBankOffset +
|
|
BANK_SIZE_2RW_WINDOW);
|
|
}
|
|
ppdev->ulWindowBank[ulWindowToMap^1] = ulBank;
|
|
}
|
|
|
|
ASSERTVGA(ppdev->flBank & BANK_PLANAR, "Should be in planar mode");
|
|
|
|
ppdev->rcl2PlanarClip[ulWindowToMap] = pbiWorking->rclBankBounds;
|
|
|
|
// Shift the bitmap start address so that the desired bank aligns with the
|
|
// banking window
|
|
|
|
if (ulWindowToMap == 0)
|
|
{
|
|
ppdev->pvBitmapStart2Window[0] =
|
|
(PVOID) ((UCHAR *)ppdev->pjScreen - pbiWorking->ulBankOffset);
|
|
}
|
|
else
|
|
{
|
|
ppdev->pvBitmapStart2Window[1] =
|
|
(PVOID) ((UCHAR *)ppdev->pjScreen - pbiWorking->ulBankOffset +
|
|
BANK_SIZE_2RW_WINDOW);
|
|
}
|
|
|
|
ppdev->flBank &= ~BANK_BROKEN_RASTERS; // No broken rasters
|
|
|
|
// Map in the desired bank; also map in the other bank to whatever its
|
|
// current state is
|
|
|
|
ppdev->ulWindowBank[ulWindowToMap] = ulBank;
|
|
|
|
// Set both banks at once, because we may have just initialized the other
|
|
// bank, and because this way the bank switch code doesn't have to do a
|
|
// read before write to obtain the state of the other bank.
|
|
// This is so convoluted to avoid problems with wiping out registers C
|
|
// thinks it's still using; the values are tranferred to volatiles, and
|
|
// then to registers
|
|
|
|
ulBank0 = ppdev->ulWindowBank[0];
|
|
ulBank1 = ppdev->ulWindowBank[1];
|
|
pBankFn = ppdev->pfnPlanarSwitchCode;
|
|
_asm mov eax,ulBank0;
|
|
_asm mov edx,ulBank1;
|
|
_asm call pBankFn; // actually switch the banks
|
|
|
|
_asm popfd;
|
|
}
|
|
|
|
|
|
/******************************Private*Routine******************************\
|
|
* vPlanarDouble
|
|
*
|
|
* Maps in two windows simultaneously, both the source window (window 0)
|
|
* and the dest window (window 1), to allows access to the scans.
|
|
* Applies to 1R1W and 2R/w window banking schemes; should never be called
|
|
* for 1 RW window schemes, because there's only one window in that case.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vPlanarDouble(
|
|
PPDEV ppdev,
|
|
LONG lScan0, // Source bank
|
|
BANK_JUST ulJustification0,// Source justification
|
|
LONG lScan1, // Destination bank
|
|
BANK_JUST ulJustification1)// Destination justification
|
|
{
|
|
PBANK_INFO pbi0;
|
|
PBANK_INFO pbi1;
|
|
ULONG ulBank0;
|
|
ULONG ulBank1;
|
|
volatile ULONG ulBank0_vol;
|
|
volatile ULONG ulBank1_vol;
|
|
volatile PFN pBankFn;
|
|
|
|
// ASM routines that call this may have STD in effect, but the C compiler
|
|
// assumes CLD
|
|
|
|
_asm pushfd
|
|
_asm cld
|
|
|
|
// Find the banks containing the scan lines with the desired justification:
|
|
|
|
if (ulJustification0 == JustifyBottom)
|
|
{
|
|
lScan0 -= ppdev->ulPlanarBottomOffset;
|
|
if (lScan0 <= 0)
|
|
lScan0 = 0;
|
|
}
|
|
if (ulJustification1 == JustifyBottom)
|
|
{
|
|
lScan1 -= ppdev->ulPlanarBottomOffset;
|
|
if (lScan1 <= 0)
|
|
lScan1 = 0;
|
|
}
|
|
|
|
ulBank0 = (ULONG) ppdev->pjJustifyTopPlanar[lScan0];
|
|
ulBank1 = (ULONG) ppdev->pjJustifyTopPlanar[lScan1];
|
|
pbi0 = &ppdev->pbiPlanarInfo[ulBank0];
|
|
pbi1 = &ppdev->pbiPlanarInfo[ulBank1];
|
|
|
|
// Set the clip rect for this bank; if it's set to -1, that indicates that
|
|
// a single-window set-up is currently active, so invalidate single-window
|
|
// clip rects and display memory pointers (when double-window is active,
|
|
// single-window is inactive, and vice-versa; a full bank set-up has to be
|
|
// performed to switch between the two)
|
|
|
|
if (ppdev->rcl2PlanarClip[0].bottom == -1)
|
|
{
|
|
if (!(ppdev->flBank & BANK_PLANAR))
|
|
{
|
|
ppdev->flBank |= BANK_PLANAR;
|
|
ppdev->pfnPlanarEnable();
|
|
}
|
|
|
|
ppdev->rcl1WindowClip.bottom = -1;
|
|
ppdev->rcl2WindowClip[0].bottom = -1;
|
|
ppdev->rcl2WindowClip[1].bottom = -1;
|
|
ppdev->rcl1PlanarClip.bottom = -1;
|
|
}
|
|
|
|
ASSERTVGA(ppdev->flBank & BANK_PLANAR, "Should be in planar mode");
|
|
|
|
ppdev->rcl2PlanarClip[0] = pbi0->rclBankBounds;
|
|
ppdev->rcl2PlanarClip[1] = pbi1->rclBankBounds;
|
|
|
|
// Shift the bitmap start address so that the desired bank aligns with the
|
|
// banking window
|
|
|
|
ppdev->pvBitmapStart2Window[0] =
|
|
(PVOID) ((UCHAR *)ppdev->pjScreen - pbi0->ulBankOffset);
|
|
ppdev->pvBitmapStart2Window[1] =
|
|
(PVOID) ((UCHAR *)ppdev->pjScreen - pbi1->ulBankOffset);
|
|
|
|
if (ppdev->vbtPlanarType == VideoBanked2RW)
|
|
{
|
|
ppdev->pvBitmapStart2Window[1] = (PVOID) ((BYTE*)
|
|
ppdev->pvBitmapStart2Window[1] + BANK_SIZE_2RW_WINDOW);
|
|
}
|
|
|
|
// Map in the desired banks.
|
|
|
|
ppdev->ulWindowBank[0] = ulBank0;
|
|
ppdev->ulWindowBank[1] = ulBank1;
|
|
|
|
ppdev->flBank &= ~BANK_BROKEN_RASTERS; // No broken rasters
|
|
|
|
// Set both banks at once.
|
|
// This is so convoluted to avoid problems with wiping out registers C
|
|
// thinks it's still using; the values are tranferred to volatiles, and
|
|
// then to registers
|
|
|
|
ulBank0_vol = ulBank0;
|
|
ulBank1_vol = ulBank1;
|
|
pBankFn = ppdev->pfnPlanarSwitchCode;
|
|
|
|
_asm mov eax,ulBank0_vol;
|
|
_asm mov edx,ulBank1_vol;
|
|
_asm call pBankFn; // actually switch the banks
|
|
|
|
_asm popfd;
|
|
}
|