1027 lines
36 KiB
C
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);
|
|
}
|
|
}
|