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