Annotation of ntddk/src/video/displays/vga256/bank.c, revision 1.1

1.1     ! root        1: /******************************Module*Header*******************************\
        !             2: * Module Name: bank.c
        !             3: *
        !             4: * Functions to control 256 colour VGA banking.
        !             5: *
        !             6: * Copyright (c) 1992 Microsoft Corporation
        !             7: \**************************************************************************/
        !             8: 
        !             9: #include "driver.h"
        !            10: #include "limits.h"
        !            11: 
        !            12: VOID vBankErrorTrap(PPDEV, LONG, BANK_JUST);
        !            13: VOID vBank2Window(PPDEV, LONG, BANK_JUST, ULONG);
        !            14: VOID vBank2Window2RW(PPDEV, LONG, BANK_JUST, ULONG);
        !            15: VOID vBank2Window1RW(PPDEV, LONG, BANK_JUST, ULONG);
        !            16: VOID vBank1Window2RW(PPDEV, LONG, BANK_JUST);
        !            17: VOID vBank1Window(PPDEV, LONG, BANK_JUST);
        !            18: VOID vPlanar2Window(PPDEV, LONG, BANK_JUST, ULONG);
        !            19: VOID vPlanar2Window2RW(PPDEV, LONG, BANK_JUST, ULONG);
        !            20: VOID vPlanar2Window1RW(PPDEV, LONG, BANK_JUST, ULONG);
        !            21: VOID vPlanar1Window2RW(PPDEV, LONG, BANK_JUST);
        !            22: VOID vPlanar1Window(PPDEV, LONG, BANK_JUST);
        !            23: 
        !            24: /******************************Public*Routine******************************\
        !            25: * bInitializeNonPlanar(ppdev, pBankInfo)
        !            26: *
        !            27: * Initialize for non-planar mode banking.
        !            28: *
        !            29: * NOTE: Allocates ppdev->pbiBankInfo and ppdev->pjJustifyTopBank buffers!
        !            30: \**************************************************************************/
        !            31: 
        !            32: BOOL bInitializeNonPlanar(PPDEV ppdev, VIDEO_BANK_SELECT* pBankInfo)
        !            33: {
        !            34:     LONG  lTotalScans;
        !            35:     LONG  lTotalBanks;
        !            36:     ULONG cjBankSize;
        !            37: 
        !            38:     ULONG cjGranularity = pBankInfo->Granularity;
        !            39:     LONG  lDelta        = pBankInfo->BitmapWidthInBytes;
        !            40:     ULONG cjBitmapSize  = pBankInfo->BitmapSize;
        !            41: 
        !            42:     ASSERTVGA(cjBitmapSize >= ppdev->cyScreen * lDelta, "Not enough vram");
        !            43: 
        !            44:     // Set up for non-planar banking:
        !            45: 
        !            46:     ppdev->lNextScan         = lDelta;
        !            47:     ppdev->vbtBankingType    = pBankInfo->BankingType;
        !            48: 
        !            49:     ppdev->pfnBankSwitchCode =
        !            50:                 (PFN) (((BYTE*)pBankInfo) + pBankInfo->CodeOffset);
        !            51: 
        !            52:     // Set all clip rects to invalid; they'll be updated when the first
        !            53:     // bank is mapped in
        !            54: 
        !            55:     ppdev->rcl1WindowClip.bottom    = -1;
        !            56:     ppdev->rcl2WindowClip[0].bottom = -1;
        !            57:     ppdev->rcl2WindowClip[1].bottom = -1;
        !            58: 
        !            59:     // Set up to call the appropriate banking control routines
        !            60: 
        !            61:     switch(pBankInfo->BankingType)
        !            62:     {
        !            63:     case VideoBanked1RW:
        !            64:         ppdev->pfnBankControl        = vBank1Window;
        !            65:         ppdev->pfnBankControl2Window = vBank2Window1RW;
        !            66:         break;
        !            67: 
        !            68:     case VideoBanked1R1W:
        !            69:         ppdev->pfnBankControl        = vBank1Window;
        !            70:         ppdev->pfnBankControl2Window = vBank2Window;
        !            71:         break;
        !            72: 
        !            73:     case VideoBanked2RW:
        !            74:         ppdev->pfnBankControl        = vBank1Window2RW;
        !            75:         ppdev->pfnBankControl2Window = vBank2Window2RW;
        !            76: 
        !            77:         // Offset from one bank index to next to make two 32k banks
        !            78:         // appear to be one seamless 64k bank:
        !            79: 
        !            80:         ppdev->ulBank2RWSkip = BANK_SIZE_2RW_WINDOW / cjGranularity;
        !            81:         break;
        !            82: 
        !            83:     default:
        !            84:         RIP("Bad BankingType");
        !            85:         return(FALSE);
        !            86:     }
        !            87: 
        !            88:     // Set up the bank control tables with clip rects for banks
        !            89:     // Note: lTotalBanks is generally an overestimate when granularity
        !            90:     // is less than window size, because we ignore any banks after the
        !            91:     // first one that includes the last scan line of the bitmap. A bit
        !            92:     // of memory could be saved by sizing lTotalBanks exactly. Note too,
        !            93:     // though, that the 2 RW window case may require more entries then,
        !            94:     // because its windows are shorter, so you'd have to make sure there
        !            95:     // were enough entries for the 2 RW window case, or recalculate
        !            96:     // lTotalBanks for the 2 RW case
        !            97: 
        !            98:     lTotalBanks = cjBitmapSize / cjGranularity;
        !            99:     lTotalScans = cjBitmapSize / lDelta;
        !           100: 
        !           101:     ppdev->cTotalScans = lTotalScans;
        !           102:     ppdev->pbiBankInfo = (PBANK_INFO) LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT,
        !           103:                           lTotalBanks * sizeof(BANK_INFO));
        !           104:     if (ppdev->pbiBankInfo == NULL)
        !           105:     {
        !           106:         RIP("Couldn't get memory for bank info");
        !           107:         return(FALSE);
        !           108:     }
        !           109: 
        !           110:     ppdev->pjJustifyTopBank = (BYTE*) LocalAlloc(LMEM_FIXED, lTotalScans);
        !           111:     if (ppdev->pjJustifyTopBank == NULL)
        !           112:     {
        !           113:         RIP("Couldn't get memory for JustifyTopBank table");
        !           114:         return(FALSE);
        !           115:     }
        !           116: 
        !           117:     // For 2 RW windows, windows are assumed to be 32k in size, otherwise
        !           118:     // assumed to be 64k:
        !           119: 
        !           120:     if (pBankInfo->BankingType == VideoBanked2RW)
        !           121:         cjBankSize = BANK_SIZE_2RW_WINDOW;
        !           122:     else
        !           123:         cjBankSize = BANK_SIZE_1_WINDOW;
        !           124: 
        !           125:     if ((cjGranularity + lDelta) >= cjBankSize &&
        !           126:         (cjGranularity % lDelta) != 0)
        !           127:     {
        !           128:         // Oh no, we've got broken rasters (where a scan line crosses
        !           129:         // a bank boundary):
        !           130: 
        !           131:         RIP("Oops, broken rasters not yet handled");
        !           132:         return(FALSE);
        !           133:     }
        !           134:     else
        !           135:     {
        !           136:         // We now fill in the scan-to-bank look-up and bank tables:
        !           137: 
        !           138:         LONG        iScan         = 0;
        !           139:         ULONG       iBank         = 0;
        !           140:         ULONG       cjScan        = 0;
        !           141:         ULONG       cjNextBank    = cjGranularity;
        !           142:         ULONG       cjEndOfBank   = cjBankSize;
        !           143:         PBANK_INFO  pbiWorking    = ppdev->pbiBankInfo;
        !           144: 
        !           145:         while (TRUE)
        !           146:         {
        !           147:             pbiWorking->ulBankOffset         = cjNextBank - cjGranularity;
        !           148: 
        !           149:         // There are no broken rasters, so don't worry about left and right
        !           150:         // edges:
        !           151: 
        !           152:             pbiWorking->rclBankBounds.left   = LONG_MIN + 1; // +1 to avoid
        !           153:                                                              // compiler warn
        !           154:             pbiWorking->rclBankBounds.right  = LONG_MAX;
        !           155:             pbiWorking->rclBankBounds.top    = iScan;
        !           156:             pbiWorking->rclBankBounds.bottom = iScan +
        !           157:                 (cjEndOfBank - cjScan) / lDelta;
        !           158: 
        !           159:             // We don't need any more banks if we can see to the end
        !           160:             // of the bitmap with the current bank:
        !           161: 
        !           162:             if (cjScan + cjBankSize >= cjBitmapSize)
        !           163:                 break;
        !           164: 
        !           165:             while (cjScan < cjNextBank)
        !           166:             {
        !           167:                 ppdev->pjJustifyTopBank[iScan++] = (BYTE) iBank;
        !           168:                 cjScan += lDelta;
        !           169:             }
        !           170: 
        !           171:             // Get ready for next bank:
        !           172: 
        !           173:             cjNextBank  += cjGranularity;
        !           174:             cjEndOfBank += cjGranularity;
        !           175:             pbiWorking++;
        !           176:             iBank++;
        !           177:         }
        !           178: 
        !           179:         // Clean up the last scans:
        !           180: 
        !           181:         ppdev->iLastBank = iBank;
        !           182:         pbiWorking->rclBankBounds.bottom = lTotalScans;
        !           183:         while (iScan < lTotalScans)
        !           184:         {
        !           185:             ppdev->pjJustifyTopBank[iScan++] = (BYTE) iBank;
        !           186:         }
        !           187: 
        !           188:         // We've just computed the precise table for JustifyTop; we now
        !           189:         // compute the scan offset for determining JustifyBottom:
        !           190: 
        !           191:         ASSERTVGA(cjBankSize >= cjGranularity,
        !           192:                "Device says granularity more than bank size?");
        !           193: 
        !           194:         ppdev->ulJustifyBottomOffset = (cjBankSize - cjGranularity) / lDelta;
        !           195: 
        !           196:         // ulJustifyBottomOffset must be less than the number of scans
        !           197:         // that fit entirely in any bank less the granularity size; if
        !           198:         // our width doesn't divide evenly into the granularity, we'll
        !           199:         // have to adjust the value to account for the first scan not
        !           200:         // starting at offset 0 in any bank:
        !           201: 
        !           202:         if ((cjGranularity % lDelta) != 0 && ppdev->ulJustifyBottomOffset > 0)
        !           203:             ppdev->ulJustifyBottomOffset--;
        !           204:     }
        !           205: 
        !           206:     return(TRUE);
        !           207: }
        !           208: 
        !           209: /******************************Public*Routine******************************\
        !           210: * bInitializePlanar(ppdev, pBankInfo)
        !           211: *
        !           212: * Initialize for non-planar mode banking.
        !           213: *
        !           214: * NOTE: Allocates ppdev->pbiPlanarInfo and ppdev->pjJustifyTopPlanar buffers!
        !           215: \**************************************************************************/
        !           216: 
        !           217: BOOL bInitializePlanar(PPDEV ppdev, VIDEO_BANK_SELECT* pBankInfo)
        !           218: {
        !           219:     LONG  lTotalScans;
        !           220:     LONG  lTotalBanks;
        !           221:     ULONG cjBankSize;
        !           222:     ULONG cjGranularity = pBankInfo->PlanarHCGranularity;
        !           223: 
        !           224:     // Since we're in planar mode, every byte we see actually represents
        !           225:     // four bytes of video memory:
        !           226: 
        !           227:     LONG  lDelta        = pBankInfo->BitmapWidthInBytes / 4;
        !           228:     ULONG cjBitmapSize  = pBankInfo->BitmapSize / 4;
        !           229: 
        !           230:     ppdev->fl |= DRIVER_PLANAR_CAPABLE;
        !           231: 
        !           232:     // Set all clip rects to invalid; they'll be updated when the first
        !           233:     // bank is mapped in
        !           234: 
        !           235:     ppdev->rcl1PlanarClip.bottom    = -1;
        !           236:     ppdev->rcl2PlanarClip[0].bottom = -1;
        !           237:     ppdev->rcl2PlanarClip[1].bottom = -1;
        !           238: 
        !           239:     // Set up for planar banking:
        !           240: 
        !           241:     ppdev->pfnPlanarSwitchCode =
        !           242:                 (PFN) (((BYTE*)pBankInfo) + pBankInfo->PlanarHCBankCodeOffset);
        !           243:     ppdev->pfnPlanarEnable     =
        !           244:                 (PFN) (((BYTE*)pBankInfo) + pBankInfo->PlanarHCEnableCodeOffset);
        !           245:     ppdev->pfnPlanarDisable     =
        !           246:                 (PFN) (((BYTE*)pBankInfo) + pBankInfo->PlanarHCDisableCodeOffset);
        !           247: 
        !           248:     ppdev->lPlanarNextScan = lDelta;
        !           249:     ppdev->vbtPlanarType   = pBankInfo->PlanarHCBankingType;
        !           250: 
        !           251:     // Set up to call the appropriate banking control routines
        !           252: 
        !           253:     switch(ppdev->vbtPlanarType)
        !           254:     {
        !           255:     case VideoBanked1RW:
        !           256:         ppdev->pfnPlanarControl  = vPlanar1Window;
        !           257:         ppdev->pfnPlanarControl2 = vPlanar2Window1RW;
        !           258:         break;
        !           259: 
        !           260:     case VideoBanked1R1W:
        !           261:         ppdev->pfnPlanarControl  = vPlanar1Window;
        !           262:         ppdev->pfnPlanarControl2 = vPlanar2Window;
        !           263:         break;
        !           264: 
        !           265:     case VideoBanked2RW:
        !           266:         ppdev->pfnPlanarControl  = vPlanar1Window2RW;
        !           267:         ppdev->pfnPlanarControl2 = vPlanar2Window2RW;
        !           268: 
        !           269:         // Offset from one bank index to next to make two 32k banks
        !           270:         // appear to be one seamless 64k bank:
        !           271: 
        !           272:         ppdev->ulPlanar2RWSkip = BANK_SIZE_2RW_WINDOW / cjGranularity;
        !           273:         break;
        !           274: 
        !           275:     default:
        !           276:         RIP("Bad BankingType");
        !           277:         return(FALSE);
        !           278:     }
        !           279: 
        !           280:     lTotalBanks = cjBitmapSize / cjGranularity;
        !           281:     lTotalScans = cjBitmapSize / lDelta;
        !           282: 
        !           283:     ppdev->pbiPlanarInfo = (PBANK_INFO) LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT,
        !           284:                           lTotalBanks * sizeof(BANK_INFO));
        !           285:     if (ppdev->pbiPlanarInfo == NULL)
        !           286:     {
        !           287:         RIP("Couldn't get memory for bank info");
        !           288:         return(FALSE);
        !           289:     }
        !           290: 
        !           291:     ppdev->pjJustifyTopPlanar = (BYTE*) LocalAlloc(LMEM_FIXED, lTotalScans);
        !           292:     if (ppdev->pjJustifyTopPlanar == NULL)
        !           293:     {
        !           294:         RIP("Couldn't get memory for JustifyTopBank table");
        !           295:         return(FALSE);
        !           296:     }
        !           297: 
        !           298:     // For 2 RW windows, windows are assumed to be 32k in size, otherwise
        !           299:     // assumed to be 64k:
        !           300: 
        !           301:     if (pBankInfo->BankingType == VideoBanked2RW)
        !           302:         cjBankSize = BANK_SIZE_2RW_WINDOW;
        !           303:     else
        !           304:         cjBankSize = BANK_SIZE_1_WINDOW;
        !           305: 
        !           306:     if ((cjGranularity + lDelta) >= cjBankSize &&
        !           307:         (cjGranularity % lDelta) != 0)
        !           308:     {
        !           309:         // Oh no, we've got broken rasters (where a scan line crosses
        !           310:         // a bank boundary):
        !           311: 
        !           312:         DISPDBG((0, "Can't handle broken planar rasters"));
        !           313: 
        !           314:         ppdev->fl &= ~DRIVER_PLANAR_CAPABLE;// !!! Temporary, until we handle
        !           315:         return(TRUE);                       // broken rasters in planar copy
        !           316:     }
        !           317:     else
        !           318:     {
        !           319:         // We now fill in the scan-to-bank look-up and bank tables:
        !           320: 
        !           321:         LONG        iScan         = 0;
        !           322:         ULONG       iBank         = 0;
        !           323:         ULONG       cjScan        = 0;
        !           324:         ULONG       cjNextBank    = cjGranularity;
        !           325:         ULONG       cjEndOfBank   = cjBankSize;
        !           326:         PBANK_INFO  pbiWorking    = ppdev->pbiPlanarInfo;
        !           327: 
        !           328:         while (TRUE)
        !           329:         {
        !           330:             pbiWorking->ulBankOffset         = cjNextBank - cjGranularity;
        !           331: 
        !           332:         // There are no broken rasters, so don't worry about left and right
        !           333:         // edges:
        !           334: 
        !           335:             pbiWorking->rclBankBounds.left   = LONG_MIN + 1; // +1 to avoid
        !           336:                                                              // compiler warn
        !           337:             pbiWorking->rclBankBounds.right  = LONG_MAX;
        !           338:             pbiWorking->rclBankBounds.top    = iScan;
        !           339:             pbiWorking->rclBankBounds.bottom = iScan +
        !           340:                 (cjEndOfBank - cjScan) / lDelta;
        !           341: 
        !           342:             // We don't need any more banks if we can see to the end
        !           343:             // of the bitmap with the current bank:
        !           344: 
        !           345:             if (cjScan + cjBankSize >= cjBitmapSize)
        !           346:                 break;
        !           347: 
        !           348:             while (cjScan < cjNextBank)
        !           349:             {
        !           350:                 ppdev->pjJustifyTopPlanar[iScan++] = (BYTE) iBank;
        !           351:                 cjScan += lDelta;
        !           352:             }
        !           353: 
        !           354:             // Get ready for next bank:
        !           355: 
        !           356:             cjNextBank  += cjGranularity;
        !           357:             cjEndOfBank += cjGranularity;
        !           358:             pbiWorking++;
        !           359:             iBank++;
        !           360:         }
        !           361: 
        !           362:         // Clean up the last scans:
        !           363: 
        !           364:         ppdev->iLastPlanar = iBank;
        !           365:         pbiWorking->rclBankBounds.bottom = lTotalScans;
        !           366:         while (iScan < lTotalScans)
        !           367:         {
        !           368:             ppdev->pjJustifyTopPlanar[iScan++] = (BYTE) iBank;
        !           369:         }
        !           370: 
        !           371:         // We've just computed the precise table for JustifyTop; we now
        !           372:         // compute the scan offset for determining JustifyBottom:
        !           373: 
        !           374:         ASSERTVGA(cjBankSize >= cjGranularity,
        !           375:                "Device says granularity more than bank size?");
        !           376: 
        !           377:         ppdev->ulPlanarBottomOffset = (cjBankSize - cjGranularity) / lDelta;
        !           378: 
        !           379:         // ulPlanarBottomOffset must be less than the number of scans
        !           380:         // that fit entirely in any bank less the granularity size; if
        !           381:         // our width doesn't divide evenly into the granularity, we'll
        !           382:         // have to adjust the value to account for the first scan not
        !           383:         // starting at offset 0 in any bank:
        !           384: 
        !           385:         if ((cjGranularity % lDelta) != 0 && ppdev->ulPlanarBottomOffset > 0)
        !           386:             ppdev->ulPlanarBottomOffset--;
        !           387:     }
        !           388: 
        !           389:     return(TRUE);
        !           390: }
        !           391: 
        !           392: /******************************Public*Routine******************************\
        !           393: * bEnableBanking(ppdev)
        !           394: *
        !           395: * Set up banking for the current mode
        !           396: * pdsurf and ppdev are the pointers to the current surface and device
        !           397: * Relevant fields in the surface are set up for banking
        !           398: \**************************************************************************/
        !           399: 
        !           400: BOOL bEnableBanking(PPDEV ppdev)
        !           401: {
        !           402:     PVIDEO_BANK_SELECT  pBankInfo;
        !           403:     UINT                ReturnedDataLength;
        !           404:     VIDEO_BANK_SELECT   TempBankInfo;
        !           405: 
        !           406:     // Make sure we've set to NULL any pointers to buffers that we allocate,
        !           407:     // so that we can free them in our error path:
        !           408: 
        !           409:     ppdev->pBankInfo          = NULL;
        !           410:     ppdev->pjJustifyTopBank   = NULL;
        !           411:     ppdev->pbiBankInfo        = NULL;
        !           412:     ppdev->pjJustifyTopPlanar = NULL;
        !           413:     ppdev->pbiPlanarInfo      = NULL;
        !           414: 
        !           415:     // Query the miniport for banking info for this mode.
        !           416:     //
        !           417:     // First, figure out how big a buffer we need for the banking info
        !           418:     // (returned in TempBankInfo->Size).
        !           419: 
        !           420:     if (!DeviceIoControl(ppdev->hDriver,
        !           421:                          IOCTL_VIDEO_GET_BANK_SELECT_CODE,
        !           422:                          NULL,                      // input buffer
        !           423:                          0,
        !           424:                          (LPVOID) &TempBankInfo,    // output buffer
        !           425:                          sizeof(VIDEO_BANK_SELECT),
        !           426:                          &ReturnedDataLength,
        !           427:                          NULL))
        !           428:     {
        !           429:         // We expect this call to fail, because we didn't allow any room
        !           430:         // for the code; we just want to get the required output buffer
        !           431:         // size. Make sure we got the expected error, ERROR_MORE_DATA.
        !           432: 
        !           433:         if (GetLastError() != ERROR_MORE_DATA)
        !           434:         {
        !           435:             RIP("Initialization error-GetBankSelectCode, first call");
        !           436:             goto error;
        !           437:         }
        !           438:     }
        !           439: 
        !           440:     // Now, allocate a buffer of the required size and get the banking info.
        !           441: 
        !           442:     pBankInfo = (PVIDEO_BANK_SELECT) LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT,
        !           443:                     TempBankInfo.Size);
        !           444:     if (pBankInfo == NULL)
        !           445:     {
        !           446:         RIP("Initialization error-couldn't get memory for bank info");
        !           447:         goto error;
        !           448:     }
        !           449: 
        !           450:     // Remember it so we can free it later:
        !           451: 
        !           452:     ppdev->pBankInfo    = pBankInfo;
        !           453: 
        !           454:     if (!DeviceIoControl(ppdev->hDriver,
        !           455:                          IOCTL_VIDEO_GET_BANK_SELECT_CODE,
        !           456:                          NULL,
        !           457:                          0,
        !           458:                          (LPVOID) pBankInfo,
        !           459:                          TempBankInfo.Size,
        !           460:                          &ReturnedDataLength,
        !           461:                          NULL))
        !           462:     {
        !           463:         RIP("Initialization error-GetBankSelectCode, second call");
        !           464:         goto error;
        !           465:     }
        !           466: 
        !           467:     // Set up for banking:
        !           468: 
        !           469:     ppdev->ulBitmapSize = pBankInfo->BitmapSize;
        !           470: 
        !           471:     if (!bInitializeNonPlanar(ppdev, pBankInfo))
        !           472:         goto error;
        !           473: 
        !           474:     if (pBankInfo->BankingFlags & PLANAR_HC)
        !           475:     {
        !           476:         ppdev->fl |= DRIVER_PLANAR_CAPABLE;
        !           477:         if (!bInitializePlanar(ppdev, pBankInfo))
        !           478:             goto error;
        !           479:     }
        !           480: 
        !           481:     // Map in scan line 0 for read & write, to put things in a known state:
        !           482: 
        !           483:     ppdev->pfnBankControl(ppdev, 0, JustifyTop);
        !           484: 
        !           485:     return(TRUE);
        !           486: 
        !           487: // Error path:
        !           488: 
        !           489: error:
        !           490:     vDisableBanking(ppdev);
        !           491: 
        !           492:     return(FALSE);
        !           493: }
        !           494: 
        !           495: /******************************Public*Routine******************************\
        !           496: * vDisableBanking(ppdev)
        !           497: *
        !           498: * Disable banking for the current mode
        !           499: \**************************************************************************/
        !           500: 
        !           501: VOID vDisableBanking(PPDEV ppdev)
        !           502: {
        !           503:     LocalFree((LPVOID) ppdev->pBankInfo);
        !           504:     LocalFree((LPVOID) ppdev->pjJustifyTopBank);
        !           505:     LocalFree((LPVOID) ppdev->pbiBankInfo);
        !           506:     LocalFree((LPVOID) ppdev->pjJustifyTopPlanar);
        !           507:     LocalFree((LPVOID) ppdev->pbiPlanarInfo);
        !           508: }
        !           509: 
        !           510: /******************************Private*Routine******************************\
        !           511: * vBankErrorTrap
        !           512: *
        !           513: * Traps calls to bank control functions in non-banked modes
        !           514: *
        !           515: \**************************************************************************/
        !           516: 
        !           517: VOID vBankErrorTrap(PPDEV ppdev, LONG lScan, BANK_JUST ulJustification)
        !           518: {
        !           519:     DISPDBG((0,"Call to bank manager in unbanked mode"));
        !           520: }
        !           521: 
        !           522: /******************************Private*Routine******************************\
        !           523: * vBank1Window
        !           524: *
        !           525: * Maps in a single R/W window that allows access to lScan. Applies to both
        !           526: * 1 RW window and 1R1W window banking schemes.
        !           527: *
        !           528: \**************************************************************************/
        !           529: 
        !           530: VOID vBank1Window(PPDEV ppdev, LONG lScan, BANK_JUST ulJustification)
        !           531: {
        !           532:              ULONG      ulBank;
        !           533:              PBANK_INFO pbiWorking;
        !           534:     volatile ULONG      ulBank0;
        !           535:     volatile PFN        pBankFn;
        !           536: 
        !           537:     // ASM routines that call this may have STD in effect, but the C compiler
        !           538:     // assumes CLD
        !           539: 
        !           540:     _asm    pushfd
        !           541:     _asm    cld
        !           542: 
        !           543:     // Set the clip rect for this bank; if it's set to -1, that indicates that
        !           544:     // a double-window set-up is currently active, so invalidate double-window
        !           545:     // clip rects and display memory pointers (when double-window is active,
        !           546:     // single-window is inactive, and vice-versa; a full bank set-up has to be
        !           547:     // performed to switch between the two)
        !           548: 
        !           549:     if (ppdev->rcl1WindowClip.bottom == -1)
        !           550:     {
        !           551:         if (ppdev->flBank & BANK_PLANAR)
        !           552:         {
        !           553:             ppdev->flBank &= ~BANK_PLANAR;
        !           554:             ppdev->pfnPlanarDisable();
        !           555:         }
        !           556: 
        !           557:         ppdev->rcl2WindowClip[0].bottom = -1;
        !           558:         ppdev->rcl2WindowClip[1].bottom = -1;
        !           559:         ppdev->rcl1PlanarClip.bottom    = -1;
        !           560:         ppdev->rcl2PlanarClip[0].bottom = -1;
        !           561:         ppdev->rcl2PlanarClip[1].bottom = -1;
        !           562:     }
        !           563: 
        !           564:     ASSERTVGA(!(ppdev->flBank & BANK_PLANAR), "Shouldn't be in planar mode");
        !           565: 
        !           566:     // Find the bank containing the scan line with the desired justification:
        !           567: 
        !           568:     {
        !           569:         register LONG lSearchScan = lScan;
        !           570:         if (ulJustification == JustifyBottom)
        !           571:         {
        !           572:             lSearchScan -= ppdev->ulJustifyBottomOffset;
        !           573:             if (lSearchScan <= 0)
        !           574:                 lSearchScan = 0;
        !           575:         }
        !           576: 
        !           577:         ulBank     = (ULONG) ppdev->pjJustifyTopBank[lSearchScan];
        !           578:         pbiWorking = &ppdev->pbiBankInfo[ulBank];
        !           579:     }
        !           580: 
        !           581:     ASSERTVGA(pbiWorking->rclBankBounds.top <= lScan &&
        !           582:            pbiWorking->rclBankBounds.bottom > lScan,
        !           583:            "Oops, scan not in bank");
        !           584: 
        !           585:     ppdev->rcl1WindowClip = pbiWorking->rclBankBounds;
        !           586: 
        !           587:     // Shift the bitmap start address so that the desired bank aligns with
        !           588:     // the banking window. The source and destination are set only so 1 R/W
        !           589:     // aligned blits will work without having to be specifically aware of
        !           590:     // the adapter type (some of the same code works with 1R/1W adapters too).
        !           591: 
        !           592:     ppdev->pvBitmapStart = (PVOID) (ppdev->pjScreen - pbiWorking->ulBankOffset);
        !           593:     ppdev->pvBitmapStart2Window[0] = ppdev->pvBitmapStart;
        !           594:     ppdev->pvBitmapStart2Window[1] = ppdev->pvBitmapStart;
        !           595: 
        !           596:     ppdev->flBank &= ~BANK_BROKEN_RASTERS;              // No broken rasters
        !           597: 
        !           598:     // Map in the desired bank for both read and write
        !           599:     // This is so convoluted to avoid problems with wiping out registers C
        !           600:     // thinks it's still using; the values are tranferred to volatiles, and
        !           601:     // then to registers
        !           602: 
        !           603:     ulBank0 = ulBank;
        !           604:     pBankFn = ppdev->pfnBankSwitchCode;
        !           605: 
        !           606:     _asm mov eax,ulBank0;
        !           607:     _asm mov edx,eax;
        !           608:     pBankFn();    // actually switch the banks
        !           609: 
        !           610:     _asm popfd
        !           611: }
        !           612: 
        !           613: /******************************Private*Routine******************************\
        !           614: * vBank1Window2RW
        !           615: *
        !           616: * Maps in two 32K RW windows so that they form a single 64K R/W window that
        !           617: * allows access to lScan. Applies only to 2 RW window schemes.
        !           618: *
        !           619: \**************************************************************************/
        !           620: 
        !           621: VOID vBank1Window2RW(PPDEV ppdev, LONG lScan, BANK_JUST ulJustification)
        !           622: {
        !           623:              ULONG      ulBank0;
        !           624:              ULONG      ulBank1;
        !           625:     volatile PFN        pBankFn;
        !           626: 
        !           627:     // ASM routines that call this may have STD in effect, but the C compiler
        !           628:     // assumes CLD
        !           629: 
        !           630:     _asm    pushfd
        !           631:     _asm    cld
        !           632: 
        !           633:     // Set the clip rect for this bank; if it's set to -1, that indicates that
        !           634:     // a double-window set-up is currently active, so invalidate double-window
        !           635:     // clip rects and display memory pointers (when double-window is active,
        !           636:     // single-window is inactive, and vice-versa; a full bank set-up has to be
        !           637:     // performed to switch between the two)
        !           638: 
        !           639:     if (ppdev->rcl1WindowClip.bottom == -1)
        !           640:     {
        !           641:         if (ppdev->flBank & BANK_PLANAR)
        !           642:         {
        !           643:             ppdev->flBank &= ~BANK_PLANAR;
        !           644:             ppdev->pfnPlanarDisable();
        !           645:         }
        !           646: 
        !           647:         ppdev->rcl2WindowClip[0].bottom = -1;
        !           648:         ppdev->rcl2WindowClip[1].bottom = -1;
        !           649:         ppdev->rcl1PlanarClip.bottom    = -1;
        !           650:         ppdev->rcl2PlanarClip[0].bottom = -1;
        !           651:         ppdev->rcl2PlanarClip[1].bottom = -1;
        !           652:     }
        !           653: 
        !           654:     ASSERTVGA(!(ppdev->flBank & BANK_PLANAR), "Shouldn't be in planar mode");
        !           655: 
        !           656:     // Find the bank containing the scan line with the desired justification:
        !           657: 
        !           658:     if (ulJustification == JustifyTop)
        !           659:     {
        !           660:         ulBank0 = ppdev->pjJustifyTopBank[lScan];
        !           661:         ulBank1 = ulBank0 + ppdev->ulBank2RWSkip;
        !           662:         if (ulBank1 >= ppdev->iLastBank)
        !           663:         {
        !           664:             ulBank1 = ppdev->iLastBank;
        !           665:             ulBank0 = ulBank1 - ppdev->ulBank2RWSkip;
        !           666:         }
        !           667:     }
        !           668:     else
        !           669:     {
        !           670:         lScan -= ppdev->ulJustifyBottomOffset;
        !           671:         if (lScan <= 0)
        !           672:             lScan = 0;
        !           673: 
        !           674:         ulBank1 = ppdev->pjJustifyTopBank[lScan];
        !           675:         ulBank0 = ulBank1 - ppdev->ulBank2RWSkip;
        !           676:         if ((LONG) ulBank0 < 0)
        !           677:         {
        !           678:             ulBank0 = 0;
        !           679:             ulBank1 = ppdev->ulBank2RWSkip;
        !           680:         }
        !           681:     }
        !           682: 
        !           683:     ppdev->rcl1WindowClip.left   = ppdev->pbiBankInfo[ulBank0].rclBankBounds.left;
        !           684:     ppdev->rcl1WindowClip.top    = ppdev->pbiBankInfo[ulBank0].rclBankBounds.top;
        !           685:     ppdev->rcl1WindowClip.bottom = ppdev->pbiBankInfo[ulBank1].rclBankBounds.bottom;
        !           686:     ppdev->rcl1WindowClip.right  = ppdev->pbiBankInfo[ulBank1].rclBankBounds.right;
        !           687: 
        !           688:     // Shift the bitmap start address so that the desired bank aligns with
        !           689:     // the banking window. The source and destination are set only so 1 R/W
        !           690:     // aligned blits will work without having to be specifically aware of
        !           691:     // the adapter type (some of the same code works with 1R/1W adapters too).
        !           692: 
        !           693:     ppdev->pvBitmapStart = (PVOID) ((BYTE*)ppdev->pjScreen
        !           694:                          - ppdev->pbiBankInfo[ulBank0].ulBankOffset);
        !           695: 
        !           696:     ppdev->pvBitmapStart2Window[0] = ppdev->pvBitmapStart;
        !           697:     ppdev->pvBitmapStart2Window[1] = ppdev->pvBitmapStart;
        !           698: 
        !           699:     ppdev->flBank &= ~BANK_BROKEN_RASTERS;              // No broken rasters
        !           700: 
        !           701:     // Map in the desired bank for both read and write; this is accomplished
        !           702:     // by mapping in the desired 32K bank, followed by the next 32K bank.
        !           703:     // This is so convoluted to avoid problems with wiping out registers C
        !           704:     // thinks it's still using; the values are tranferred to volatiles, and
        !           705:     // then to registers
        !           706: 
        !           707:     pBankFn = ppdev->pfnBankSwitchCode;
        !           708: 
        !           709:     _asm mov eax,ulBank0;
        !           710:     _asm mov edx,ulBank1;
        !           711:     pBankFn();    // actually switch the banks
        !           712: 
        !           713:     _asm popfd;
        !           714: }
        !           715: 
        !           716: /******************************Private*Routine******************************\
        !           717: * vBank2Window
        !           718: *
        !           719: * Maps in one of two windows, either the source window (window 0) or the dest
        !           720: * window (window 1), to allows access to lScan. Applies to 1R1W window
        !           721: * banking scheme; should never be called for 1 RW window schemes, because
        !           722: * there's only one window in that case.
        !           723: *
        !           724: \**************************************************************************/
        !           725: 
        !           726: VOID vBank2Window(
        !           727:     PPDEV       ppdev,
        !           728:     LONG        lScan,
        !           729:     BANK_JUST   ulJustification,
        !           730:     ULONG       ulWindowToMap)
        !           731: {
        !           732:              ULONG       ulBank;
        !           733:              PBANK_INFO  pbiWorking;
        !           734:     volatile ULONG       ulBank0;
        !           735:     volatile ULONG       ulBank1;
        !           736:     volatile PFN         pBankFn;
        !           737: 
        !           738:     // ASM routines that call this may have STD in effect, but the C compiler
        !           739:     // assumes CLD
        !           740: 
        !           741:     _asm    pushfd
        !           742:     _asm    cld
        !           743: 
        !           744:     // Find the bank containing the scan line with the desired justification:
        !           745: 
        !           746:     if (ulJustification == JustifyBottom)
        !           747:     {
        !           748:         lScan -= ppdev->ulJustifyBottomOffset;
        !           749:         if (lScan <= 0)
        !           750:             lScan = 0;
        !           751:     }
        !           752: 
        !           753:     ulBank     = (ULONG) ppdev->pjJustifyTopBank[lScan];
        !           754:     pbiWorking = &ppdev->pbiBankInfo[ulBank];
        !           755: 
        !           756:     // Set the clip rect for this bank; if it's set to -1, that indicates that
        !           757:     // a single-window set-up is currently active, so invalidate single-window
        !           758:     // clip rects and display memory pointers (when double-window is active,
        !           759:     // single-window is inactive, and vice-versa; a full bank set-up has to be
        !           760:     // performed to switch between the two)
        !           761: 
        !           762:     if (ppdev->rcl2WindowClip[ulWindowToMap].bottom == -1)
        !           763:     {
        !           764:         ULONG ulOtherWindow = ulWindowToMap ^ 1;
        !           765: 
        !           766:         if (ppdev->flBank & BANK_PLANAR)
        !           767:         {
        !           768:             ppdev->flBank &= ~BANK_PLANAR;
        !           769:             ppdev->pfnPlanarDisable();
        !           770:         }
        !           771: 
        !           772:         ppdev->rcl1WindowClip.bottom    = -1;
        !           773:         ppdev->rcl1PlanarClip.bottom    = -1;
        !           774:         ppdev->rcl2PlanarClip[0].bottom = -1;
        !           775:         ppdev->rcl2PlanarClip[1].bottom = -1;
        !           776: 
        !           777:         // Neither of the 2 window windows was active, so we have to set up the
        !           778:         // variables for the other bank (the one other than the one we were
        !           779:         // called to set) as well, to make it valid. The other bank is set to
        !           780:         // the same state as the bank we were called to set
        !           781: 
        !           782:         ppdev->rcl2WindowClip[ulOtherWindow]       = pbiWorking->rclBankBounds;
        !           783:         ppdev->ulWindowBank[ulOtherWindow]         = ulBank;
        !           784:         ppdev->pvBitmapStart2Window[ulOtherWindow] =
        !           785:                 (PVOID) ((BYTE*)ppdev->pjScreen - pbiWorking->ulBankOffset);
        !           786:     }
        !           787: 
        !           788:     ASSERTVGA(!(ppdev->flBank & BANK_PLANAR), "Shouldn't be in planar mode");
        !           789: 
        !           790:     ppdev->rcl2WindowClip[ulWindowToMap] = pbiWorking->rclBankBounds;
        !           791: 
        !           792:     // Shift the bitmap start address so that the desired bank aligns with the
        !           793:     // banking window
        !           794: 
        !           795:     ppdev->pvBitmapStart2Window[ulWindowToMap] =
        !           796:             (PVOID) ((UCHAR *)ppdev->pjScreen - pbiWorking->ulBankOffset);
        !           797: 
        !           798:     // Map in the desired bank; also map in the other bank to whatever its
        !           799:     // current state is
        !           800: 
        !           801:     ppdev->ulWindowBank[ulWindowToMap] = ulBank;
        !           802: 
        !           803:     ppdev->flBank &= ~BANK_BROKEN_RASTERS;              // No broken rasters
        !           804: 
        !           805:     // Set both banks at once, because we may have just initialized the other
        !           806:     // bank, and because this way the bank switch code doesn't have to do a
        !           807:     // read before write to obtain the state of the other bank.
        !           808:     // This is so convoluted to avoid problems with wiping out registers C
        !           809:     // thinks it's still using; the values are tranferred to volatiles, and
        !           810:     // then to registers
        !           811: 
        !           812: 
        !           813:     ulBank0 = ppdev->ulWindowBank[0];
        !           814:     ulBank1 = ppdev->ulWindowBank[1];
        !           815:     pBankFn = ppdev->pfnBankSwitchCode;
        !           816: 
        !           817:     _asm mov eax,ulBank0;
        !           818:     _asm mov edx,ulBank1;
        !           819:     pBankFn();    // actually switch the banks
        !           820: 
        !           821:     _asm popfd;
        !           822: }
        !           823: 
        !           824: /******************************Private*Routine******************************\
        !           825: * vBank2Window1RW
        !           826: *
        !           827: * Maps in the one window in 1R/W case.  Does exactly the same thing as the
        !           828: * one window case, because there's only one window, but has to be a separate
        !           829: * entry point because of the extra parameter (because we're using STDCALL).
        !           830: \**************************************************************************/
        !           831: 
        !           832: VOID vBank2Window1RW(PPDEV ppdev, LONG lScan,
        !           833:     BANK_JUST ulJustification, ULONG ulWindowToMap)
        !           834: {
        !           835:     vBank1Window(ppdev, lScan, ulJustification);
        !           836: }
        !           837: 
        !           838: /******************************Private*Routine******************************\
        !           839: * vBank2Window2RW
        !           840: *
        !           841: * Maps in one of two windows, either the source window (window 0) or the dest
        !           842: * window (window 1), to allows access to lScan. Applies to 2RW window
        !           843: * banking scheme; should never be called for 1 RW window schemes, because
        !           844: * there's only one window in that case.
        !           845: \**************************************************************************/
        !           846: 
        !           847: VOID vBank2Window2RW(
        !           848:     PPDEV       ppdev,
        !           849:     LONG        lScan,
        !           850:     BANK_JUST   ulJustification,
        !           851:     ULONG       ulWindowToMap)
        !           852: {
        !           853:              ULONG      ulBank;
        !           854:              PBANK_INFO pbiWorking;
        !           855:     volatile ULONG      ulBank0;
        !           856:     volatile ULONG      ulBank1;
        !           857:     volatile PFN        pBankFn;
        !           858: 
        !           859:     // ASM routines that call this may have STD in effect, but the C compiler
        !           860:     // assumes CLD
        !           861: 
        !           862:     _asm    pushfd
        !           863:     _asm    cld
        !           864: 
        !           865:     // Find the bank containing the scan line with the desired justification:
        !           866: 
        !           867:     if (ulJustification == JustifyBottom)
        !           868:     {
        !           869:         lScan -= ppdev->ulJustifyBottomOffset;
        !           870:         if (lScan <= 0)
        !           871:             lScan = 0;
        !           872:     }
        !           873: 
        !           874:     ulBank     = (ULONG) ppdev->pjJustifyTopBank[lScan];
        !           875:     pbiWorking = &ppdev->pbiBankInfo[ulBank];
        !           876: 
        !           877:     // Set the clip rect for this bank; if it's set to -1, that indicates that
        !           878:     // a single-window set-up is currently active, so invalidate single-window
        !           879:     // clip rects and display memory pointers (when double-window is active,
        !           880:     // single-window is inactive, and vice-versa; a full bank set-up has to be
        !           881:     // performed to switch between the two)
        !           882: 
        !           883:     if (ppdev->rcl2WindowClip[ulWindowToMap].bottom == -1)
        !           884:     {
        !           885:         if (ppdev->flBank & BANK_PLANAR)
        !           886:         {
        !           887:             ppdev->flBank &= ~BANK_PLANAR;
        !           888:             ppdev->pfnPlanarDisable();
        !           889:         }
        !           890: 
        !           891:         ppdev->rcl1WindowClip.bottom    = -1;
        !           892:         ppdev->rcl1PlanarClip.bottom    = -1;
        !           893:         ppdev->rcl2PlanarClip[0].bottom = -1;
        !           894:         ppdev->rcl2PlanarClip[1].bottom = -1;
        !           895: 
        !           896:         // Neither of the 2 window windows was active, so we have to set up the
        !           897:         // variables for the other bank (the one other than the one we were
        !           898:         // called to set) as well, to make it valid. The other bank is set to
        !           899:         // the same state as the bank we were called to set
        !           900: 
        !           901:         ppdev->rcl2WindowClip[ulWindowToMap^1] = pbiWorking->rclBankBounds;
        !           902:         if (ulWindowToMap == 1)
        !           903:         {
        !           904:             ppdev->pvBitmapStart2Window[0] =
        !           905:                 (PVOID) ((BYTE*)ppdev->pjScreen - pbiWorking->ulBankOffset);
        !           906:         }
        !           907:         else
        !           908:         {
        !           909:             ppdev->pvBitmapStart2Window[1] =
        !           910:                 (PVOID) ((UCHAR *)ppdev->pjScreen - pbiWorking->ulBankOffset +
        !           911:                 BANK_SIZE_2RW_WINDOW);
        !           912:         }
        !           913:         ppdev->ulWindowBank[ulWindowToMap^1] = ulBank;
        !           914:     }
        !           915: 
        !           916:     ASSERTVGA(!(ppdev->flBank & BANK_PLANAR), "Shouldn't be in planar mode");
        !           917: 
        !           918:     ppdev->rcl2WindowClip[ulWindowToMap] = pbiWorking->rclBankBounds;
        !           919: 
        !           920:     // Shift the bitmap start address so that the desired bank aligns with the
        !           921:     // banking window
        !           922: 
        !           923:     if (ulWindowToMap == 0)
        !           924:     {
        !           925:         ppdev->pvBitmapStart2Window[0] =
        !           926:             (PVOID) ((UCHAR *)ppdev->pjScreen - pbiWorking->ulBankOffset);
        !           927:     }
        !           928:     else
        !           929:     {
        !           930:         ppdev->pvBitmapStart2Window[1] =
        !           931:             (PVOID) ((UCHAR *)ppdev->pjScreen - pbiWorking->ulBankOffset +
        !           932:             BANK_SIZE_2RW_WINDOW);
        !           933:     }
        !           934: 
        !           935:     ppdev->flBank &= ~BANK_BROKEN_RASTERS;              // No broken rasters
        !           936: 
        !           937:     // Map in the desired bank; also map in the other bank to whatever its
        !           938:     // current state is
        !           939: 
        !           940:     ppdev->ulWindowBank[ulWindowToMap] = ulBank;
        !           941: 
        !           942:     // Set both banks at once, because we may have just initialized the other
        !           943:     // bank, and because this way the bank switch code doesn't have to do a
        !           944:     // read before write to obtain the state of the other bank.
        !           945:     // This is so convoluted to avoid problems with wiping out registers C
        !           946:     // thinks it's still using; the values are tranferred to volatiles, and
        !           947:     // then to registers
        !           948: 
        !           949:     ulBank0 = ppdev->ulWindowBank[0];
        !           950:     ulBank1 = ppdev->ulWindowBank[1];
        !           951:     pBankFn = ppdev->pfnBankSwitchCode;
        !           952:     _asm mov eax,ulBank0;
        !           953:     _asm mov edx,ulBank1;
        !           954:     pBankFn();    // actually switch the banks
        !           955: 
        !           956:     _asm popfd;
        !           957: }
        !           958: 
        !           959: /******************************Private*Routine******************************\
        !           960: * vPlanar1Window
        !           961: *
        !           962: * Maps in a single R/W window that allows access to lScan. Applies to both
        !           963: * 1 RW window and 1R1W window banking schemes.
        !           964: \**************************************************************************/
        !           965: 
        !           966: VOID vPlanar1Window(PPDEV ppdev, LONG lScan, BANK_JUST ulJustification)
        !           967: {
        !           968:              ULONG      ulBank;
        !           969:              PBANK_INFO pbiWorking;
        !           970:     volatile ULONG      ulBank0;
        !           971:     volatile PFN        pBankFn;
        !           972: 
        !           973:     // ASM routines that call this may have STD in effect, but the C compiler
        !           974:     // assumes CLD
        !           975: 
        !           976:     _asm    pushfd
        !           977:     _asm    cld
        !           978: 
        !           979:     // Set the clip rect for this bank; if it's set to -1, that indicates that
        !           980:     // a double-window set-up is currently active, so invalidate double-window
        !           981:     // clip rects and display memory pointers (when double-window is active,
        !           982:     // single-window is inactive, and vice-versa; a full bank set-up has to be
        !           983:     // performed to switch between the two)
        !           984: 
        !           985:     if (ppdev->rcl1PlanarClip.bottom == -1)
        !           986:     {
        !           987:         if (!(ppdev->flBank & BANK_PLANAR))
        !           988:         {
        !           989:             ppdev->flBank |= BANK_PLANAR;
        !           990:             ppdev->pfnPlanarEnable();
        !           991:         }
        !           992: 
        !           993:         ppdev->rcl1WindowClip.bottom    = -1;
        !           994:         ppdev->rcl2WindowClip[0].bottom = -1;
        !           995:         ppdev->rcl2WindowClip[1].bottom = -1;
        !           996:         ppdev->rcl2PlanarClip[0].bottom = -1;
        !           997:         ppdev->rcl2PlanarClip[1].bottom = -1;
        !           998:     }
        !           999: 
        !          1000:     ASSERTVGA(ppdev->flBank & BANK_PLANAR, "Should be in planar mode");
        !          1001: 
        !          1002:     // Find the bank containing the scan line with the desired justification:
        !          1003: 
        !          1004:     if (ulJustification == JustifyBottom)
        !          1005:     {
        !          1006:         lScan -= ppdev->ulPlanarBottomOffset;
        !          1007:         if (lScan <= 0)
        !          1008:             lScan = 0;
        !          1009:     }
        !          1010: 
        !          1011:     ulBank     = (ULONG) ppdev->pjJustifyTopPlanar[lScan];
        !          1012:     pbiWorking = &ppdev->pbiPlanarInfo[ulBank];
        !          1013: 
        !          1014:     ppdev->rcl1PlanarClip = pbiWorking->rclBankBounds;
        !          1015: 
        !          1016:     // Shift the bitmap start address so that the desired bank aligns with
        !          1017:     // the banking window. The source and destination are set only so 1 R/W
        !          1018:     // aligned blits will work without having to be specifically aware of
        !          1019:     // the adapter type (some of the same code works with 1R/1W adapters too).
        !          1020: 
        !          1021:     ppdev->pvBitmapStart = (PVOID) (ppdev->pjScreen - pbiWorking->ulBankOffset);
        !          1022:     ppdev->pvBitmapStart2Window[0] = ppdev->pvBitmapStart;
        !          1023:     ppdev->pvBitmapStart2Window[1] = ppdev->pvBitmapStart;
        !          1024: 
        !          1025:     ppdev->flBank &= ~BANK_BROKEN_RASTERS;              // No broken rasters
        !          1026: 
        !          1027:     // Map in the desired bank for both read and write
        !          1028:     // This is so convoluted to avoid problems with wiping out registers C
        !          1029:     // thinks it's still using; the values are tranferred to volatiles, and
        !          1030:     // then to registers
        !          1031: 
        !          1032:     ulBank0 = ulBank;
        !          1033:     pBankFn = ppdev->pfnPlanarSwitchCode;
        !          1034: 
        !          1035:     _asm mov eax,ulBank0;
        !          1036:     _asm mov edx,eax;
        !          1037:     pBankFn();    // actually switch the banks
        !          1038: 
        !          1039:     _asm popfd
        !          1040: }
        !          1041: 
        !          1042: /******************************Private*Routine******************************\
        !          1043: * vPlanar1Window2RW
        !          1044: *
        !          1045: * Maps in two 32K RW windows so that they form a single 64K R/W window that
        !          1046: * allows access to lScan. Applies only to 2 RW window schemes.
        !          1047: *
        !          1048: \**************************************************************************/
        !          1049: 
        !          1050: VOID vPlanar1Window2RW(PPDEV ppdev, LONG lScan, BANK_JUST ulJustification)
        !          1051: {
        !          1052:              ULONG      ulBank0;
        !          1053:              ULONG      ulBank1;
        !          1054:     volatile PFN        pBankFn;
        !          1055: 
        !          1056:     // ASM routines that call this may have STD in effect, but the C compiler
        !          1057:     // assumes CLD
        !          1058: 
        !          1059:     _asm    pushfd
        !          1060:     _asm    cld
        !          1061: 
        !          1062:     // Set the clip rect for this bank; if it's set to -1, that indicates that
        !          1063:     // a double-window set-up is currently active, so invalidate double-window
        !          1064:     // clip rects and display memory pointers (when double-window is active,
        !          1065:     // single-window is inactive, and vice-versa; a full bank set-up has to be
        !          1066:     // performed to switch between the two)
        !          1067: 
        !          1068: 
        !          1069:     if (ppdev->rcl1PlanarClip.bottom == -1)
        !          1070:     {
        !          1071:         if (!(ppdev->flBank & BANK_PLANAR))
        !          1072:         {
        !          1073:             ppdev->flBank |= BANK_PLANAR;
        !          1074:             ppdev->pfnPlanarEnable();
        !          1075:         }
        !          1076: 
        !          1077:         ppdev->rcl1WindowClip.bottom    = -1;
        !          1078:         ppdev->rcl2WindowClip[0].bottom = -1;
        !          1079:         ppdev->rcl2WindowClip[1].bottom = -1;
        !          1080:         ppdev->rcl2PlanarClip[0].bottom = -1;
        !          1081:         ppdev->rcl2PlanarClip[1].bottom = -1;
        !          1082:     }
        !          1083: 
        !          1084:     ASSERTVGA(ppdev->flBank & BANK_PLANAR, "Should be in planar mode");
        !          1085: 
        !          1086:     // Find the bank containing the scan line with the desired justification:
        !          1087: 
        !          1088:     if (ulJustification == JustifyTop)
        !          1089:     {
        !          1090:         ulBank0 = ppdev->pjJustifyTopPlanar[lScan];
        !          1091:         ulBank1 = ulBank0 + ppdev->ulPlanar2RWSkip;
        !          1092:         if (ulBank1 >= ppdev->iLastPlanar)
        !          1093:             ulBank1 = ppdev->iLastPlanar;
        !          1094:     }
        !          1095:     else
        !          1096:     {
        !          1097:         lScan -= ppdev->ulPlanarBottomOffset;
        !          1098:         if (lScan <= 0)
        !          1099:             lScan = 0;
        !          1100: 
        !          1101:         ulBank1 = ppdev->pjJustifyTopPlanar[lScan];
        !          1102:         ulBank0 = ulBank1 - ppdev->ulPlanar2RWSkip;
        !          1103:         if ((LONG) ulBank0 < 0)
        !          1104:             ulBank0 = 0;
        !          1105:     }
        !          1106: 
        !          1107:     ppdev->rcl1PlanarClip.left   = ppdev->pbiPlanarInfo[ulBank0].rclBankBounds.left;
        !          1108:     ppdev->rcl1PlanarClip.top    = ppdev->pbiPlanarInfo[ulBank0].rclBankBounds.top;
        !          1109:     ppdev->rcl1PlanarClip.bottom = ppdev->pbiPlanarInfo[ulBank1].rclBankBounds.bottom;
        !          1110:     ppdev->rcl1PlanarClip.right  = ppdev->pbiPlanarInfo[ulBank1].rclBankBounds.right;
        !          1111: 
        !          1112:     // Shift the bitmap start address so that the desired bank aligns with
        !          1113:     // the banking window. The source and destination are set only so 1 R/W
        !          1114:     // aligned blits will work without having to be specifically aware of
        !          1115:     // the adapter type (some of the same code works with 1R/1W adapters too).
        !          1116: 
        !          1117:     ppdev->pvBitmapStart = (PVOID) ((BYTE*)ppdev->pjScreen
        !          1118:                          - ppdev->pbiPlanarInfo[ulBank0].ulBankOffset);
        !          1119: 
        !          1120:     ppdev->pvBitmapStart2Window[0] = ppdev->pvBitmapStart;
        !          1121:     ppdev->pvBitmapStart2Window[1] = ppdev->pvBitmapStart;
        !          1122: 
        !          1123:     ppdev->flBank &= ~BANK_BROKEN_RASTERS;              // No broken rasters
        !          1124: 
        !          1125:     // Map in the desired bank for both read and write; this is accomplished
        !          1126:     // by mapping in the desired 32K bank, followed by the next 32K bank.
        !          1127:     // This is so convoluted to avoid problems with wiping out registers C
        !          1128:     // thinks it's still using; the values are tranferred to volatiles, and
        !          1129:     // then to registers
        !          1130: 
        !          1131:     pBankFn = ppdev->pfnPlanarSwitchCode;
        !          1132: 
        !          1133:     _asm mov eax,ulBank0;
        !          1134:     _asm mov edx,ulBank1;
        !          1135:     pBankFn();    // actually switch the banks
        !          1136: 
        !          1137:     _asm popfd;
        !          1138: }
        !          1139: 
        !          1140: /******************************Private*Routine******************************\
        !          1141: * vPlanar2Window
        !          1142: *
        !          1143: * Maps in one of two windows, either the source window (window 0) or the dest
        !          1144: * window (window 1), to allows access to lScan. Applies to 1R1W window
        !          1145: * banking scheme; should never be called for 1 RW window schemes, because
        !          1146: * there's only one window in that case.
        !          1147: *
        !          1148: \**************************************************************************/
        !          1149: 
        !          1150: VOID vPlanar2Window(
        !          1151:     PPDEV       ppdev,
        !          1152:     LONG        lScan,
        !          1153:     BANK_JUST   ulJustification,
        !          1154:     ULONG       ulWindowToMap)
        !          1155: {
        !          1156:              ULONG       ulBank;
        !          1157:              PBANK_INFO  pbiWorking;
        !          1158:     volatile ULONG       ulBank0;
        !          1159:     volatile ULONG       ulBank1;
        !          1160:     volatile PFN         pBankFn;
        !          1161: 
        !          1162:     // ASM routines that call this may have STD in effect, but the C compiler
        !          1163:     // assumes CLD
        !          1164: 
        !          1165:     _asm    pushfd
        !          1166:     _asm    cld
        !          1167: 
        !          1168:     // Find the bank containing the scan line with the desired justification:
        !          1169: 
        !          1170:     if (ulJustification == JustifyBottom)
        !          1171:     {
        !          1172:         lScan -= ppdev->ulPlanarBottomOffset;
        !          1173:         if (lScan <= 0)
        !          1174:             lScan = 0;
        !          1175:     }
        !          1176: 
        !          1177:     ulBank     = (ULONG) ppdev->pjJustifyTopPlanar[lScan];
        !          1178:     pbiWorking = &ppdev->pbiPlanarInfo[ulBank];
        !          1179: 
        !          1180:     // Set the clip rect for this bank; if it's set to -1, that indicates that
        !          1181:     // a single-window set-up is currently active, so invalidate single-window
        !          1182:     // clip rects and display memory pointers (when double-window is active,
        !          1183:     // single-window is inactive, and vice-versa; a full bank set-up has to be
        !          1184:     // performed to switch between the two)
        !          1185: 
        !          1186:     if (ppdev->rcl2PlanarClip[ulWindowToMap].bottom == -1)
        !          1187:     {
        !          1188:         ULONG ulOtherWindow = ulWindowToMap ^ 1;
        !          1189: 
        !          1190:         if (!(ppdev->flBank & BANK_PLANAR))
        !          1191:         {
        !          1192:             ppdev->flBank |= BANK_PLANAR;
        !          1193:             ppdev->pfnPlanarEnable();
        !          1194:         }
        !          1195: 
        !          1196:         ppdev->rcl1WindowClip.bottom    = -1;
        !          1197:         ppdev->rcl2WindowClip[0].bottom = -1;
        !          1198:         ppdev->rcl2WindowClip[1].bottom = -1;
        !          1199:         ppdev->rcl1PlanarClip.bottom    = -1;
        !          1200: 
        !          1201:         // Neither of the 2 window windows was active, so we have to set up the
        !          1202:         // variables for the other bank (the one other than the one we were
        !          1203:         // called to set) as well, to make it valid. The other bank is set to
        !          1204:         // the same state as the bank we were called to set
        !          1205: 
        !          1206:         ppdev->rcl2PlanarClip[ulOtherWindow]       = pbiWorking->rclBankBounds;
        !          1207:         ppdev->ulWindowBank[ulOtherWindow]         = ulBank;
        !          1208:         ppdev->pvBitmapStart2Window[ulOtherWindow] =
        !          1209:                 (PVOID) ((BYTE*)ppdev->pjScreen - pbiWorking->ulBankOffset);
        !          1210:     }
        !          1211: 
        !          1212:     ASSERTVGA(ppdev->flBank & BANK_PLANAR, "Should be in planar mode");
        !          1213: 
        !          1214:     ppdev->rcl2PlanarClip[ulWindowToMap] = pbiWorking->rclBankBounds;
        !          1215: 
        !          1216:     // Shift the bitmap start address so that the desired bank aligns with the
        !          1217:     // banking window
        !          1218: 
        !          1219:     ppdev->pvBitmapStart2Window[ulWindowToMap] =
        !          1220:             (PVOID) ((UCHAR *)ppdev->pjScreen - pbiWorking->ulBankOffset);
        !          1221: 
        !          1222:     // Map in the desired bank; also map in the other bank to whatever its
        !          1223:     // current state is
        !          1224: 
        !          1225:     ppdev->ulWindowBank[ulWindowToMap] = ulBank;
        !          1226: 
        !          1227:     ppdev->flBank &= ~BANK_BROKEN_RASTERS;              // No broken rasters
        !          1228: 
        !          1229:     // Set both banks at once, because we may have just initialized the other
        !          1230:     // bank, and because this way the bank switch code doesn't have to do a
        !          1231:     // read before write to obtain the state of the other bank.
        !          1232:     // This is so convoluted to avoid problems with wiping out registers C
        !          1233:     // thinks it's still using; the values are tranferred to volatiles, and
        !          1234:     // then to registers
        !          1235: 
        !          1236: 
        !          1237:     ulBank0 = ppdev->ulWindowBank[0];
        !          1238:     ulBank1 = ppdev->ulWindowBank[1];
        !          1239:     pBankFn = ppdev->pfnPlanarSwitchCode;
        !          1240: 
        !          1241:     _asm mov eax,ulBank0;
        !          1242:     _asm mov edx,ulBank1;
        !          1243:     pBankFn();    // actually switch the banks
        !          1244: 
        !          1245:     _asm popfd;
        !          1246: }
        !          1247: 
        !          1248: /******************************Private*Routine******************************\
        !          1249: * vPlanar2Window1RW
        !          1250: *
        !          1251: * Maps in the one window in 1R/W case.  Does exactly the same thing as the
        !          1252: * one window case, because there's only one window, but has to be a separate
        !          1253: * entry point because of the extra parameter (because we're using STDCALL).
        !          1254: \**************************************************************************/
        !          1255: 
        !          1256: VOID vPlanar2Window1RW(PPDEV ppdev, LONG lScan,
        !          1257:     BANK_JUST ulJustification, ULONG ulWindowToMap)
        !          1258: {
        !          1259:     vPlanar1Window(ppdev, lScan, ulJustification);
        !          1260: }
        !          1261: 
        !          1262: /******************************Private*Routine******************************\
        !          1263: * vPlanar2Window2RW
        !          1264: *
        !          1265: * Maps in one of two windows, either the source window (window 0) or the dest
        !          1266: * window (window 1), to allows access to lScan. Applies to 2RW window
        !          1267: * banking scheme; should never be called for 1 RW window schemes, because
        !          1268: * there's only one window in that case.
        !          1269: \**************************************************************************/
        !          1270: 
        !          1271: VOID vPlanar2Window2RW(
        !          1272:     PPDEV       ppdev,
        !          1273:     LONG        lScan,
        !          1274:     BANK_JUST   ulJustification,
        !          1275:     ULONG       ulWindowToMap)
        !          1276: {
        !          1277:              ULONG      ulBank;
        !          1278:              PBANK_INFO pbiWorking;
        !          1279:     volatile ULONG      ulBank0;
        !          1280:     volatile ULONG      ulBank1;
        !          1281:     volatile PFN        pBankFn;
        !          1282: 
        !          1283:     // ASM routines that call this may have STD in effect, but the C compiler
        !          1284:     // assumes CLD
        !          1285: 
        !          1286:     _asm    pushfd
        !          1287:     _asm    cld
        !          1288: 
        !          1289:     // Find the bank containing the scan line with the desired justification:
        !          1290: 
        !          1291:     if (ulJustification == JustifyBottom)
        !          1292:     {
        !          1293:         lScan -= ppdev->ulPlanarBottomOffset;
        !          1294:         if (lScan <= 0)
        !          1295:             lScan = 0;
        !          1296:     }
        !          1297: 
        !          1298:     ulBank     = (ULONG) ppdev->pjJustifyTopPlanar[lScan];
        !          1299:     pbiWorking = &ppdev->pbiPlanarInfo[ulBank];
        !          1300: 
        !          1301:     // Set the clip rect for this bank; if it's set to -1, that indicates that
        !          1302:     // a single-window set-up is currently active, so invalidate single-window
        !          1303:     // clip rects and display memory pointers (when double-window is active,
        !          1304:     // single-window is inactive, and vice-versa; a full bank set-up has to be
        !          1305:     // performed to switch between the two)
        !          1306: 
        !          1307:     if (ppdev->rcl2PlanarClip[ulWindowToMap].bottom == -1)
        !          1308:     {
        !          1309:         if (!(ppdev->flBank & BANK_PLANAR))
        !          1310:         {
        !          1311:             ppdev->flBank |= BANK_PLANAR;
        !          1312:             ppdev->pfnPlanarEnable();
        !          1313:         }
        !          1314: 
        !          1315:         ppdev->rcl1WindowClip.bottom    = -1;
        !          1316:         ppdev->rcl2WindowClip[0].bottom = -1;
        !          1317:         ppdev->rcl2WindowClip[1].bottom = -1;
        !          1318:         ppdev->rcl1PlanarClip.bottom    = -1;
        !          1319: 
        !          1320:         // Neither of the 2 window windows was active, so we have to set up the
        !          1321:         // variables for the other bank (the one other than the one we were
        !          1322:         // called to set) as well, to make it valid. The other bank is set to
        !          1323:         // the same state as the bank we were called to set
        !          1324: 
        !          1325:         ppdev->rcl2PlanarClip[ulWindowToMap^1] = pbiWorking->rclBankBounds;
        !          1326:         if (ulWindowToMap == 1)
        !          1327:         {
        !          1328:             ppdev->pvBitmapStart2Window[0] =
        !          1329:                 (PVOID) ((BYTE*)ppdev->pjScreen - pbiWorking->ulBankOffset);
        !          1330:         }
        !          1331:         else
        !          1332:         {
        !          1333:             ppdev->pvBitmapStart2Window[1] =
        !          1334:                 (PVOID) ((UCHAR *)ppdev->pjScreen - pbiWorking->ulBankOffset +
        !          1335:                 BANK_SIZE_2RW_WINDOW);
        !          1336:         }
        !          1337:         ppdev->ulWindowBank[ulWindowToMap^1] = ulBank;
        !          1338:     }
        !          1339: 
        !          1340:     ASSERTVGA(ppdev->flBank & BANK_PLANAR, "Should be in planar mode");
        !          1341: 
        !          1342:     ppdev->rcl2PlanarClip[ulWindowToMap] = pbiWorking->rclBankBounds;
        !          1343: 
        !          1344:     // Shift the bitmap start address so that the desired bank aligns with the
        !          1345:     // banking window
        !          1346: 
        !          1347:     if (ulWindowToMap == 0)
        !          1348:     {
        !          1349:         ppdev->pvBitmapStart2Window[0] =
        !          1350:             (PVOID) ((UCHAR *)ppdev->pjScreen - pbiWorking->ulBankOffset);
        !          1351:     }
        !          1352:     else
        !          1353:     {
        !          1354:         ppdev->pvBitmapStart2Window[1] =
        !          1355:             (PVOID) ((UCHAR *)ppdev->pjScreen - pbiWorking->ulBankOffset +
        !          1356:             BANK_SIZE_2RW_WINDOW);
        !          1357:     }
        !          1358: 
        !          1359:     ppdev->flBank &= ~BANK_BROKEN_RASTERS;              // No broken rasters
        !          1360: 
        !          1361:     // Map in the desired bank; also map in the other bank to whatever its
        !          1362:     // current state is
        !          1363: 
        !          1364:     ppdev->ulWindowBank[ulWindowToMap] = ulBank;
        !          1365: 
        !          1366:     // Set both banks at once, because we may have just initialized the other
        !          1367:     // bank, and because this way the bank switch code doesn't have to do a
        !          1368:     // read before write to obtain the state of the other bank.
        !          1369:     // This is so convoluted to avoid problems with wiping out registers C
        !          1370:     // thinks it's still using; the values are tranferred to volatiles, and
        !          1371:     // then to registers
        !          1372: 
        !          1373:     ulBank0 = ppdev->ulWindowBank[0];
        !          1374:     ulBank1 = ppdev->ulWindowBank[1];
        !          1375:     pBankFn = ppdev->pfnPlanarSwitchCode;
        !          1376:     _asm mov eax,ulBank0;
        !          1377:     _asm mov edx,ulBank1;
        !          1378:     pBankFn();    // actually switch the banks
        !          1379: 
        !          1380:     _asm popfd;
        !          1381: }
        !          1382: 
        !          1383: 
        !          1384: /******************************Private*Routine******************************\
        !          1385: * vPlanarDouble
        !          1386: *
        !          1387: * Maps in two windows simultaneously, both the source window (window 0)
        !          1388: * and the dest window (window 1), to allows access to the scans.
        !          1389: * Applies to 1R1W and 2R/w window banking schemes; should never be called
        !          1390: * for 1 RW window schemes, because there's only one window in that case.
        !          1391: *
        !          1392: \**************************************************************************/
        !          1393: 
        !          1394: VOID vPlanarDouble(
        !          1395:     PPDEV       ppdev,
        !          1396:     LONG        lScan0,          // Source bank
        !          1397:     BANK_JUST   ulJustification0,// Source justification
        !          1398:     LONG        lScan1,          // Destination bank
        !          1399:     BANK_JUST   ulJustification1)// Destination justification
        !          1400: {
        !          1401:              PBANK_INFO  pbi0;
        !          1402:              PBANK_INFO  pbi1;
        !          1403:              ULONG       ulBank0;
        !          1404:              ULONG       ulBank1;
        !          1405:     volatile ULONG       ulBank0_vol;
        !          1406:     volatile ULONG       ulBank1_vol;
        !          1407:     volatile PFN         pBankFn;
        !          1408: 
        !          1409:     // ASM routines that call this may have STD in effect, but the C compiler
        !          1410:     // assumes CLD
        !          1411: 
        !          1412:     _asm    pushfd
        !          1413:     _asm    cld
        !          1414: 
        !          1415:     // Find the banks containing the scan lines with the desired justification:
        !          1416: 
        !          1417:     if (ulJustification0 == JustifyBottom)
        !          1418:     {
        !          1419:         lScan0 -= ppdev->ulPlanarBottomOffset;
        !          1420:         if (lScan0 <= 0)
        !          1421:             lScan0 = 0;
        !          1422:     }
        !          1423:     if (ulJustification1 == JustifyBottom)
        !          1424:     {
        !          1425:         lScan1 -= ppdev->ulPlanarBottomOffset;
        !          1426:         if (lScan1 <= 0)
        !          1427:             lScan1 = 0;
        !          1428:     }
        !          1429: 
        !          1430:     ulBank0    = (ULONG) ppdev->pjJustifyTopPlanar[lScan0];
        !          1431:     ulBank1    = (ULONG) ppdev->pjJustifyTopPlanar[lScan1];
        !          1432:     pbi0       = &ppdev->pbiPlanarInfo[ulBank0];
        !          1433:     pbi1       = &ppdev->pbiPlanarInfo[ulBank1];
        !          1434: 
        !          1435:     // Set the clip rect for this bank; if it's set to -1, that indicates that
        !          1436:     // a single-window set-up is currently active, so invalidate single-window
        !          1437:     // clip rects and display memory pointers (when double-window is active,
        !          1438:     // single-window is inactive, and vice-versa; a full bank set-up has to be
        !          1439:     // performed to switch between the two)
        !          1440: 
        !          1441:     if (ppdev->rcl2PlanarClip[0].bottom == -1)
        !          1442:     {
        !          1443:         if (!(ppdev->flBank & BANK_PLANAR))
        !          1444:         {
        !          1445:             ppdev->flBank |= BANK_PLANAR;
        !          1446:             ppdev->pfnPlanarEnable();
        !          1447:         }
        !          1448: 
        !          1449:         ppdev->rcl1WindowClip.bottom    = -1;
        !          1450:         ppdev->rcl2WindowClip[0].bottom = -1;
        !          1451:         ppdev->rcl2WindowClip[1].bottom = -1;
        !          1452:         ppdev->rcl1PlanarClip.bottom    = -1;
        !          1453:     }
        !          1454: 
        !          1455:     ASSERTVGA(ppdev->flBank & BANK_PLANAR, "Should be in planar mode");
        !          1456: 
        !          1457:     ppdev->rcl2PlanarClip[0] = pbi0->rclBankBounds;
        !          1458:     ppdev->rcl2PlanarClip[1] = pbi1->rclBankBounds;
        !          1459: 
        !          1460:     // Shift the bitmap start address so that the desired bank aligns with the
        !          1461:     // banking window
        !          1462: 
        !          1463:     ppdev->pvBitmapStart2Window[0] =
        !          1464:             (PVOID) ((UCHAR *)ppdev->pjScreen - pbi0->ulBankOffset);
        !          1465:     ppdev->pvBitmapStart2Window[1] =
        !          1466:             (PVOID) ((UCHAR *)ppdev->pjScreen - pbi1->ulBankOffset);
        !          1467: 
        !          1468:     if (ppdev->vbtPlanarType == VideoBanked2RW)
        !          1469:     {
        !          1470:         ppdev->pvBitmapStart2Window[1] = (PVOID) ((BYTE*)
        !          1471:             ppdev->pvBitmapStart2Window[1] + BANK_SIZE_2RW_WINDOW);
        !          1472:     }
        !          1473: 
        !          1474:     // Map in the desired banks.
        !          1475: 
        !          1476:     ppdev->ulWindowBank[0] = ulBank0;
        !          1477:     ppdev->ulWindowBank[1] = ulBank1;
        !          1478: 
        !          1479:     ppdev->flBank &= ~BANK_BROKEN_RASTERS;              // No broken rasters
        !          1480: 
        !          1481:     // Set both banks at once.
        !          1482:     // This is so convoluted to avoid problems with wiping out registers C
        !          1483:     // thinks it's still using; the values are tranferred to volatiles, and
        !          1484:     // then to registers
        !          1485: 
        !          1486:     ulBank0_vol = ulBank0;
        !          1487:     ulBank1_vol = ulBank1;
        !          1488:     pBankFn = ppdev->pfnPlanarSwitchCode;
        !          1489: 
        !          1490:     _asm mov eax,ulBank0_vol;
        !          1491:     _asm mov edx,ulBank1_vol;
        !          1492:     pBankFn();    // actually switch the banks
        !          1493: 
        !          1494:     _asm popfd;
        !          1495: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.