2025-04-27 07:49:33 -04:00

1027 lines
36 KiB
C

/******************************Module*Header*******************************\
* Module Name: bank.c
*
* Functions to control VGA banking
*
* Copyright (c) 1992-1995 Microsoft Corporation
\**************************************************************************/
#include "driver.h" // private driver defines
void BankErrorTrap(PDEVSURF, LONG, BANK_JUST);
void Bank2Window(PDEVSURF, LONG, BANK_JUST, ULONG);
void Bank2Window2RW(PDEVSURF, LONG, BANK_JUST, ULONG);
void Bank2Window1RW(PDEVSURF, LONG, BANK_JUST, ULONG);
void Bank1Window2RW(PDEVSURF, LONG, BANK_JUST);
void Bank1Window(PDEVSURF, LONG, BANK_JUST);
LPBYTE pPtrWork;
LPBYTE pPtrSave;
/******************************Public*Routine******************************\
* SetUpBanking
*
* 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 SetUpBanking(PDEVSURF pdsurf, PPDEV ppdev)
{
INT i;
LONG lTemp;
LONG lScansPerBank, lScan, lTotalScans, lTotalBanks;
LONG lScansBetweenBanks;
ULONG ulOffset;
PVIDEO_BANK_SELECT BankInfo;
UINT ReturnedDataLength;
VIDEO_BANK_SELECT TempBankInfo;
PBANK_INFO pbiWorking;
DWORD status;
//
// 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,
0,
&TempBankInfo,
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.
//
if (status != ERROR_MORE_DATA) {
//
// Should post error and return FALSE
//
//RIP("Initialization error-GetBankSelectCode, first call\n");
//return FALSE;
}
}
//
// Now, allocate a buffer of the required size and get the banking info.
//
if ((BankInfo = (PVIDEO_BANK_SELECT)
EngAllocMem(0, TempBankInfo.Size, ALLOC_TAG)) == NULL) {
//
// Should post error and return FALSE
//
RIP("Initialization error-couldn't get memory for bank info\n");
return FALSE;
}
if (EngDeviceIoControl(ppdev->hDriver,
IOCTL_VIDEO_GET_BANK_SELECT_CODE,
NULL,
0,
BankInfo,
TempBankInfo.Size,
&ReturnedDataLength)) {
//
// Should post error and return FALSE
//
RIP("Initialization error-GetBankSelectCode, second call\n");
return FALSE;
}
//
// Set up for banking.
//
// Set up variables that are the same whether the adapter is banked or not
pdsurf->pBankSelectInfo = BankInfo;
pdsurf->pfnBankSwitchCode =
(PFN) (((UCHAR *)BankInfo) + BankInfo->CodeOffset);
pdsurf->vbtBankingType = BankInfo->BankingType;
pdsurf->ulBitmapSize = BankInfo->BitmapSize;
pdsurf->lNextScan = BankInfo->BitmapWidthInBytes;
// Set up the pointer off-screen work areas at the very end of display
// memory (values are relative to bitmap start)
ppdev->pPtrWork = pPtrWork = (LPBYTE) pdsurf->ulBitmapSize - POINTER_WORK_AREA_SIZE;
ppdev->pPtrSave = pPtrSave = pPtrWork - POINTER_SAVE_AREA_SIZE;
ppdev->sizlMem.cx = BankInfo->BitmapWidthInBytes *
(PLANAR_PELS_PER_CPU_ADDRESS);
ppdev->sizlMem.cy = BankInfo->BitmapSize / BankInfo->BitmapWidthInBytes;
DISPDBG((1,"ppdev->sizlMem.cx = %lu\n",ppdev->sizlMem.cx));
DISPDBG((1,"ppdev->sizlMem.cy = %lu\n",ppdev->sizlMem.cy));
DISPDBG((1,"BankInfo->Size = %lu\n",BankInfo->Size));
DISPDBG((1,"BankInfo->Length = %lu\n",BankInfo->Length));
//
// calculate how many scans of offscreen memory are used by the pointer
//
ppdev->cNumScansUsedByPointer =
(POINTER_SAVE_AREA_SIZE + POINTER_WORK_AREA_SIZE +
BankInfo->BitmapWidthInBytes - 1) /
(BankInfo->BitmapWidthInBytes);
DISPDBG((1,"Software pointer uses %lu scans\n", ppdev->cNumScansUsedByPointer));
//
// for 1280x1024x16 in 1M, check to see that we actually have the
// scans to put the pointer in offscreen video memory. If not,
// lie and set flag that keeps the driver from trying.
//
if ((LONG)ppdev->cNumScansUsedByPointer > (ppdev->sizlMem.cy - ppdev->sizlSurf.cy))
{
ppdev->fl &= ~DRIVER_OFFSCREEN_REFRESHED;
}
// Set up info that depends on whether or not the adapter is banked
if (BankInfo->BankingType == VideoNotBanked) {
lTotalScans = BankInfo->BitmapSize / BankInfo->BitmapWidthInBytes;
// Unbanked; set all clip rects for the full bitmap, so the bank never
// needs to be changed, and set the banking vectors to error traps,
// since they should never be called
pdsurf->rcl1WindowClip.left = pdsurf->rcl2WindowClip[0].left =
pdsurf->rcl2WindowClip[1].left = pdsurf->rcl1WindowClip.top =
pdsurf->rcl2WindowClip[0].top = pdsurf->rcl2WindowClip[1].top = 0;
pdsurf->rcl1WindowClip.right = pdsurf->rcl2WindowClip[0].right =
pdsurf->rcl2WindowClip[1].right =
BankInfo->BitmapWidthInBytes << 8;
pdsurf->rcl1WindowClip.bottom = pdsurf->rcl2WindowClip[0].bottom =
pdsurf->rcl2WindowClip[1].bottom = lTotalScans;
pdsurf->pfnBankControl = BankErrorTrap;
pdsurf->pfnBankControl2Window = BankErrorTrap;
pdsurf->ulWindowBank[0] = pdsurf->ulWindowBank[1] = (ULONG)0;
pdsurf->pvBitmapStart = pdsurf->pvBitmapStart2Window[0] =
pdsurf->pvBitmapStart2Window[1] = pdsurf->pvStart;
// Scan line to be used with JustifyBottom to map in the bank
// containing the pointer work and save areas, which are guaranteed not
// to span banks. Is only used to determine that the bank never needs
// to be changed to map in the pointer in unbanked case
pdsurf->ulPtrBankScan = 0;
// Mark that the bank info pointers are unused, so we don't try to
// deallocate the memory they point to
pdsurf->pbiBankInfo = pdsurf->pbiBankInfo2RW = NULL;
// Allocate space for the temp buffer.
if ((pdsurf->pvBankBufferPlane0 =
(PVOID) EngAllocMem(0, BANK_BUFFER_SIZE_UNBANKED, ALLOC_TAG))
== NULL) {
//
// Should post error and return FALSE
//
RIP("Couldn't get memory for temp buffer");
return FALSE;
}
pdsurf->ulTempBufferSize = BANK_BUFFER_SIZE_UNBANKED;
// These should never be used
pdsurf->pvBankBufferPlane1 =
pdsurf->pvBankBufferPlane2 =
pdsurf->pvBankBufferPlane3 = (PVOID) NULL;
} else {
// Banked, so set up all banking variables and initialize the bank
// control routines and their data tables
// Reject if there are broken rasters (a broken raster is a scan line
// that crosses a bank boundary); that's not handled in this driver
if (BankInfo->BankingType != VideoBanked2RW) {
// For the 1 RW window and 1R1W window cases, windows are
// assumed to be BANK_SIZE_1_WINDOW in size (generally 64K)
lTemp = BANK_SIZE_1_WINDOW;
} else {
// For the 2 RW window case, windows are assumed to be
// BANK_SIZE_2RW_WINDOW in size (generally 32K)
lTemp = BANK_SIZE_2RW_WINDOW;
}
if ((lTemp % BankInfo->BitmapWidthInBytes) != 0) {
//
// Should post error and return FALSE
//
RIP("Broken rasters not supported");
return FALSE;
}
// These will be set properly on first call to bank controller, below,
// or something's wrong
pdsurf->ulWindowBank[0] = (ULONG)-1;
pdsurf->ulWindowBank[1] = (ULONG)-1;
pdsurf->pvBitmapStart = pdsurf->pvBitmapStart2Window[0] =
pdsurf->pvBitmapStart2Window[1] = (PVOID) 0;
// Set all clip rects to invalid; they'll be updated when the first
// bank is mapped in
pdsurf->rcl1WindowClip.left = pdsurf->rcl2WindowClip[0].left =
pdsurf->rcl2WindowClip[1].left = pdsurf->rcl1WindowClip.top =
pdsurf->rcl2WindowClip[0].top = pdsurf->rcl2WindowClip[1].top =
pdsurf->rcl1WindowClip.right = pdsurf->rcl2WindowClip[0].right =
pdsurf->rcl2WindowClip[1].right = pdsurf->rcl1WindowClip.bottom =
pdsurf->rcl2WindowClip[0].bottom =
pdsurf->rcl2WindowClip[1].bottom = -1;
// Set up to call the appropriate banking control routines
switch(BankInfo->BankingType) {
case VideoBanked1RW:
pdsurf->pfnBankControl = Bank1Window;
pdsurf->pfnBankControl2Window = Bank2Window1RW;
if ((pdsurf->pvBankBufferPlane0 =
(PVOID) EngAllocMem(0, BANK_BUFFER_SIZE_1RW, ALLOC_TAG))
== NULL) {
//
// Should post error and return FALSE
//
RIP("Couldn't get memory for temp buffer");
return FALSE;
}
pdsurf->ulTempBufferSize = BANK_BUFFER_SIZE_1RW;
pdsurf->pvBankBufferPlane1 =
((LPBYTE)pdsurf->pvBankBufferPlane0) +
BANK_BUFFER_PLANE_SIZE;
pdsurf->pvBankBufferPlane2 =
((LPBYTE)pdsurf->pvBankBufferPlane1) +
BANK_BUFFER_PLANE_SIZE;
pdsurf->pvBankBufferPlane3 =
((LPBYTE)pdsurf->pvBankBufferPlane2) +
BANK_BUFFER_PLANE_SIZE;
break;
case VideoBanked1R1W:
pdsurf->pfnBankControl = Bank1Window;
pdsurf->pfnBankControl2Window = Bank2Window;
if ((pdsurf->pvBankBufferPlane0 =
(PVOID) EngAllocMem(0, BANK_BUFFER_SIZE_1R1W, ALLOC_TAG))
== NULL) {
//
// Should post error and return FALSE
//
RIP("Couldn't get memory for temp buffer");
return FALSE;
}
pdsurf->ulTempBufferSize = BANK_BUFFER_SIZE_1R1W;
// These should never be used
pdsurf->pvBankBufferPlane1 =
pdsurf->pvBankBufferPlane2 =
pdsurf->pvBankBufferPlane3 = (PVOID) NULL;
break;
case VideoBanked2RW:
pdsurf->pfnBankControl = Bank1Window2RW;
pdsurf->pfnBankControl2Window = Bank2Window2RW;
if ((pdsurf->pvBankBufferPlane0 =
(PVOID) EngAllocMem(0, BANK_BUFFER_SIZE_2RW, ALLOC_TAG))
== NULL) {
//
// Should post error and return FALSE
//
RIP("Couldn't get memory for temp buffer");
return FALSE;
}
pdsurf->ulTempBufferSize = BANK_BUFFER_SIZE_2RW;
// These should never be used
pdsurf->pvBankBufferPlane1 =
pdsurf->pvBankBufferPlane2 =
pdsurf->pvBankBufferPlane3 = (PVOID) NULL;
break;
default:
//
// Should post error and return FALSE
//
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 = BankInfo->BitmapSize / BankInfo->Granularity;
lTotalScans = BankInfo->BitmapSize / BankInfo->BitmapWidthInBytes;
lScansBetweenBanks =
BankInfo->Granularity / BankInfo->BitmapWidthInBytes;
// Allocate memory for bank control info
if ((pdsurf->pbiBankInfo = (PBANK_INFO)
EngAllocMem(0, lTotalBanks * sizeof(BANK_INFO), ALLOC_TAG))
== NULL) {
//
// Should post error and return FALSE
//
RIP("Couldn't get memory for bank info #2");
return FALSE;
}
// Build the list of bank rects & offsets assuming standard window
// size
lScansPerBank = BANK_SIZE_1_WINDOW / BankInfo->BitmapWidthInBytes;
ulOffset = 0;
lScan = -lScansBetweenBanks; // precompensate for 1st time in loop
i = 0;
pbiWorking = pdsurf->pbiBankInfo;
do {
lScan += lScansBetweenBanks;
pbiWorking->rclBankBounds.left = 0;
pbiWorking->rclBankBounds.right = pdsurf->sizlSurf.cx;
pbiWorking->rclBankBounds.top = lScan;
pbiWorking->rclBankBounds.bottom = lScan + lScansPerBank;
pbiWorking->ulBankOffset = ulOffset;
ulOffset += BankInfo->Granularity;
i++;
pbiWorking++;
} while ((lScan + lScansPerBank) < lTotalScans);
pdsurf->ulBankInfoLength = i;
// If this is a 2RW bank adapter, build a table for that too, with
// 32K windows
if (BankInfo->BankingType == VideoBanked2RW) {
// Offset from one bank index to next to make two 32K banks
// appear to be one seamless 64K bank
pdsurf->ulBank2RWSkip =
(BANK_SIZE_2RW_WINDOW / BankInfo->Granularity);
// Allocate memory for 2RW case bank control info
if ((pdsurf->pbiBankInfo2RW =
(PBANK_INFO) EngAllocMem(0, lTotalBanks * sizeof(BANK_INFO), ALLOC_TAG))
== NULL) {
//
// Should post error and return FALSE
//
RIP("Couldn't get memory for bank info #3");
return FALSE;
}
// Build the list of bank rects & offsets for 2RW case
lScansPerBank =
BANK_SIZE_2RW_WINDOW / BankInfo->BitmapWidthInBytes;
lScan = -lScansBetweenBanks; // precompensate for 1st time
ulOffset = 0;
i = 0;
pbiWorking = pdsurf->pbiBankInfo2RW;
do {
lScan += lScansBetweenBanks;
pbiWorking->rclBankBounds.left = 0;
pbiWorking->rclBankBounds.right = pdsurf->sizlSurf.cx;
pbiWorking->rclBankBounds.top = lScan;
pbiWorking->rclBankBounds.bottom = lScan + lScansPerBank;
pbiWorking->ulBankOffset = ulOffset;
ulOffset += BankInfo->Granularity;
i++;
pbiWorking++;
} while ((lScan + lScansPerBank) < lTotalScans);
pdsurf->ulBankInfo2RWLength = i;
} else {
// Not a 2RW bank adapter
pdsurf->pbiBankInfo2RW = NULL;
pdsurf->ulBankInfo2RWLength = 0;
}
// Map in scan line 0 for read & write, to put things in a known state
pdsurf->pfnBankControl(pdsurf, 0, JustifyTop);
// Scan line to be used with JustifyBottom to map in the bank
// containing the pointer work and save areas, which are guaranteed not
// to span banks
pdsurf->ulPtrBankScan = (pdsurf->ulBitmapSize/pdsurf->lNextScan) - 1;
}
return TRUE;
}
/******************************Private*Routine******************************\
* BankErrorTrap
*
* Traps calls to bank control functions in non-banked modes
*
\**************************************************************************/
void BankErrorTrap(PDEVSURF pdsurf, LONG lScan,
BANK_JUST ulJustification)
{
DISPDBG((0, "Call to bank manager in unbanked mode\n"));
}
/******************************Private*Routine******************************\
* Bank1Window
*
* Maps in a single R/W window that allows access to lScan. Applies to both
* 1 RW window and 1R1W window banking schemes.
*
* Note: in the 1 R/W adapter case, this may be called with a fourth parameter
* (the source/dest selector), which is ignored. This is so that we can use the
* same routine as the destination for 1 R/W 2-window calls; those calls don't
* map in separate banks, of course, but they let us get away with common code
* for 1 R/W and 1R/1W in some cases (such as aligned blits).
*
\**************************************************************************/
void Bank1Window(PDEVSURF pdsurf, LONG 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
// Find the bank containing the scan line with the desired justification
if (ulJustification == JustifyTop) {
// Map scan line in as near as possible to the top of the window
ulBank = pdsurf->ulBankInfoLength-1;
pbiWorking = pdsurf->pbiBankInfo + ulBank;
while (pbiWorking->rclBankBounds.top > lScan) {
ulBank--;
pbiWorking--;
}
} else {
// Map scan line in as near as possible to the bottom of the window
ulBank = 0;
pbiWorking = pdsurf->pbiBankInfo;
while (pbiWorking->rclBankBounds.bottom <= lScan) {
ulBank++;
pbiWorking++;
}
}
// 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 (pdsurf->rcl1WindowClip.top == -1) {
pdsurf->rcl2WindowClip[0].top =
pdsurf->rcl2WindowClip[0].bottom =
pdsurf->rcl2WindowClip[0].right =
pdsurf->rcl2WindowClip[0].left =
pdsurf->rcl2WindowClip[1].top =
pdsurf->rcl2WindowClip[1].bottom =
pdsurf->rcl2WindowClip[1].right =
pdsurf->rcl2WindowClip[1].left = -1;
pdsurf->pvBitmapStart2Window[0] = (PDEVSURF) 0;
pdsurf->pvBitmapStart2Window[1] = (PDEVSURF) 0;
} else {
// ASSERT(pdsurf->rcl2WindowClip[0].top == -1,
// "BANK.C: 2 bank src not mapped out");
// ASSERT(pdsurf->rcl2WindowClip[1].top == -1,
// "BANK.C: 2 bank src not mapped out");
}
pdsurf->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).
pdsurf->pvBitmapStart =
pdsurf->pvBitmapStart2Window[0] =
pdsurf->pvBitmapStart2Window[1] =
(PVOID) ((UCHAR *)pdsurf->pvStart - pbiWorking->ulBankOffset);
// 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 = pdsurf->pfnBankSwitchCode;
_asm mov eax,ulBank0;
_asm mov edx,eax;
_asm call pBankFn; // actually switch the banks
_asm popfd
}
/******************************Private*Routine******************************\
* Bank1Window2RW
*
* 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 Bank1Window2RW(PDEVSURF pdsurf, LONG lScan,
BANK_JUST ulJustification)
{
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 == JustifyTop) {
// Map scan line in as near as possible to the top of the window
ulBank = pdsurf->ulBankInfoLength-1;
pbiWorking = pdsurf->pbiBankInfo + ulBank;
while (pbiWorking->rclBankBounds.top > lScan) {
ulBank--;
pbiWorking--;
}
} else {
// Map scan line in as near as possible to the bottom of the window
ulBank = 0;
pbiWorking = pdsurf->pbiBankInfo;
while (pbiWorking->rclBankBounds.bottom <= lScan) {
ulBank++;
pbiWorking++;
}
}
// 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 (pdsurf->rcl1WindowClip.top == -1) {
pdsurf->rcl2WindowClip[0].top =
pdsurf->rcl2WindowClip[0].bottom =
pdsurf->rcl2WindowClip[0].right =
pdsurf->rcl2WindowClip[0].left =
pdsurf->rcl2WindowClip[1].top =
pdsurf->rcl2WindowClip[1].bottom =
pdsurf->rcl2WindowClip[1].right =
pdsurf->rcl2WindowClip[1].left = -1;
pdsurf->pvBitmapStart2Window[0] = (PDEVSURF) 0;
pdsurf->pvBitmapStart2Window[1] = (PDEVSURF) 0;
} else {
// ASSERT(pdsurf->rcl2WindowClip[0].top == -1,
// "BANK.C: 2 bank src not mapped out");
// ASSERT(pdsurf->rcl2WindowClip[1].top == -1,
// "BANK.C: 2 bank src not mapped out");
}
pdsurf->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).
pdsurf->pvBitmapStart =
pdsurf->pvBitmapStart2Window[0] =
pdsurf->pvBitmapStart2Window[1] =
(PVOID) ((UCHAR *)pdsurf->pvStart - pbiWorking->ulBankOffset);
// 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
ulBank0 = ulBank;
ulBank1 = ulBank0 + pdsurf->ulBank2RWSkip;
pBankFn = pdsurf->pfnBankSwitchCode;
_asm mov eax,ulBank0;
_asm mov edx,ulBank1;
_asm call pBankFn; // actually switch the banks
_asm popfd
}
/******************************Private*Routine******************************\
* Bank2Window
*
* 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 Bank2Window(PDEVSURF pdsurf, LONG lScan,
BANK_JUST ulJustification, ULONG ulWindowToMap)
{
ULONG ulBank;
PBANK_INFO pbiWorking;
volatile ULONG ulBank0, 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 == JustifyTop) {
// Map scan line in as near as possible to the top of the window
ulBank = pdsurf->ulBankInfoLength-1;
pbiWorking = pdsurf->pbiBankInfo + ulBank;
while (pbiWorking->rclBankBounds.top > lScan) {
ulBank--;
pbiWorking--;
}
} else {
// Map scan line in as near as possible to the bottom of the window
ulBank = 0;
pbiWorking = pdsurf->pbiBankInfo;
while (pbiWorking->rclBankBounds.bottom <= lScan) {
ulBank++;
pbiWorking++;
}
}
// 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 (pdsurf->rcl2WindowClip[ulWindowToMap].top == -1) {
pdsurf->rcl1WindowClip.top =
pdsurf->rcl1WindowClip.bottom =
pdsurf->rcl1WindowClip.right =
pdsurf->rcl1WindowClip.left = -1;
pdsurf->pvBitmapStart = (PDEVSURF) 0;
// 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
pdsurf->rcl2WindowClip[ulWindowToMap^1] = pbiWorking->rclBankBounds;
pdsurf->pvBitmapStart2Window[ulWindowToMap^1] =
(PVOID) ((UCHAR *)pdsurf->pvStart - pbiWorking->ulBankOffset);
pdsurf->ulWindowBank[ulWindowToMap^1] = ulBank;
} else {
// ASSERT(pdsurf->rcl1WindowClip.top == -1,
// "BANK.C: 1 bank not mapped out");
}
pdsurf->rcl2WindowClip[ulWindowToMap] = pbiWorking->rclBankBounds;
// Shift the bitmap start address so that the desired bank aligns with the
// banking window
pdsurf->pvBitmapStart2Window[ulWindowToMap] =
(PVOID) ((UCHAR *)pdsurf->pvStart - pbiWorking->ulBankOffset);
// Map in the desired bank; also map in the other bank to whatever its
// current state is
pdsurf->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 = pdsurf->ulWindowBank[0];
ulBank1 = pdsurf->ulWindowBank[1];
pBankFn = pdsurf->pfnBankSwitchCode;
_asm mov eax,ulBank0;
_asm mov edx,ulBank1;
_asm call pBankFn; // actually switch the banks
_asm popfd
}
/******************************Private*Routine******************************\
* Bank2Window1RW
*
* 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 Bank2Window1RW(PDEVSURF pdsurf, LONG lScan,
BANK_JUST ulJustification, ULONG ulWindowToMap)
{
Bank1Window(pdsurf, lScan, ulJustification);
}
/******************************Private*Routine******************************\
* Bank2Window2RW
*
* 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 Bank2Window2RW(PDEVSURF pdsurf, LONG lScan,
BANK_JUST ulJustification, ULONG ulWindowToMap)
{
ULONG ulBank;
PBANK_INFO pbiWorking;
volatile ULONG ulBank0, 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 == JustifyTop) {
// Map scan line in as near as possible to the top of the window
ulBank = pdsurf->ulBankInfo2RWLength-1;
pbiWorking = pdsurf->pbiBankInfo2RW + ulBank;
while (pbiWorking->rclBankBounds.top > lScan) {
ulBank--;
pbiWorking--;
}
} else {
// Map scan line in as near as possible to the bottom of the window
ulBank = 0;
pbiWorking = pdsurf->pbiBankInfo2RW;
while (pbiWorking->rclBankBounds.bottom <= lScan) {
ulBank++;
pbiWorking++;
}
}
// 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 (pdsurf->rcl2WindowClip[ulWindowToMap].top == -1) {
pdsurf->rcl1WindowClip.top =
pdsurf->rcl1WindowClip.bottom =
pdsurf->rcl1WindowClip.right =
pdsurf->rcl1WindowClip.left = -1;
pdsurf->pvBitmapStart = (PDEVSURF) 0;
// 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
pdsurf->rcl2WindowClip[ulWindowToMap^1] = pbiWorking->rclBankBounds;
if (ulWindowToMap == 1) {
pdsurf->pvBitmapStart2Window[0] =
(PVOID) ((UCHAR *)pdsurf->pvStart - pbiWorking->ulBankOffset);
} else {
pdsurf->pvBitmapStart2Window[1] =
(PVOID) ((UCHAR *)pdsurf->pvStart - pbiWorking->ulBankOffset +
BANK_SIZE_2RW_WINDOW);
}
pdsurf->ulWindowBank[ulWindowToMap^1] = ulBank;
} else {
// ASSERT(pdsurf->rcl1WindowClip.top == -1,
// "BANK.C: 1 bank not mapped out");
}
pdsurf->rcl2WindowClip[ulWindowToMap] = pbiWorking->rclBankBounds;
// Shift the bitmap start address so that the desired bank aligns with the
// banking window
if (ulWindowToMap == 0) {
pdsurf->pvBitmapStart2Window[0] =
(PVOID) ((UCHAR *)pdsurf->pvStart - pbiWorking->ulBankOffset);
} else {
pdsurf->pvBitmapStart2Window[1] =
(PVOID) ((UCHAR *)pdsurf->pvStart - pbiWorking->ulBankOffset +
BANK_SIZE_2RW_WINDOW);
}
// Map in the desired bank; also map in the other bank to whatever its
// current state is
pdsurf->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 = pdsurf->ulWindowBank[0];
ulBank1 = pdsurf->ulWindowBank[1];
pBankFn = pdsurf->pfnBankSwitchCode;
_asm mov eax,ulBank0;
_asm mov edx,ulBank1;
_asm call pBankFn; // actually switch the banks
_asm popfd
}
/************************************************************************\
* DrvIntersectRect
*
* Calculates the intersection between *prcSrc1 and *prcSrc2,
* returning the resulting rect in *prcDst. Returns TRUE if
* *prcSrc1 intersects *prcSrc2, FALSE otherwise. If there is no
* intersection, an empty rect is returned in *prcDst
\************************************************************************/
static const RECTL rclEmpty = { 0, 0, 0, 0 };
BOOL DrvIntersectRect(
PRECTL prcDst,
PRECTL prcSrc1,
PRECTL prcSrc2)
{
prcDst->left = max(prcSrc1->left, prcSrc2->left);
prcDst->right = min(prcSrc1->right, prcSrc2->right);
/*
* check for empty rect
*/
if (prcDst->left < prcDst->right) {
prcDst->top = max(prcSrc1->top, prcSrc2->top);
prcDst->bottom = min(prcSrc1->bottom, prcSrc2->bottom);
/*
* check for empty rect
*/
if (prcDst->top < prcDst->bottom) {
return TRUE; // not empty
}
}
/*
* empty rect
*/
*prcDst = rclEmpty;
return FALSE;
}
/************************************************************************\
* vForceBank0
*
* Forces the VGA to map in bank 0 if there's banking. Intended for use
* when returning from fullscreen, so a known bank is mapped.
\************************************************************************/
VOID vForceBank0(
PPDEV ppdev)
{
PDEVSURF pdsurf = ppdev->pdsurf;
if (pdsurf->vbtBankingType != VideoNotBanked) {
// Set all clip rects to invalid; they'll be updated when we map in
// bank 0
pdsurf->rcl1WindowClip.left = pdsurf->rcl2WindowClip[0].left =
pdsurf->rcl2WindowClip[1].left = pdsurf->rcl1WindowClip.top =
pdsurf->rcl2WindowClip[0].top = pdsurf->rcl2WindowClip[1].top =
pdsurf->rcl1WindowClip.right = pdsurf->rcl2WindowClip[0].right =
pdsurf->rcl2WindowClip[1].right = pdsurf->rcl1WindowClip.bottom =
pdsurf->rcl2WindowClip[0].bottom =
pdsurf->rcl2WindowClip[1].bottom = -1;
// Map in scan line 0 for read & write, to put things in a known state
pdsurf->pfnBankControl(pdsurf, 0, JustifyTop);
}
}