Leaked source code of windows server 2003
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

/******************************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;
}