File:  [WindowsNT SDKs] / ntddk / src / video / displays / s3 / bankmgr.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Thu Aug 9 18:31:12 2018 UTC (7 years, 9 months ago) by root
Branches: msft, MAIN
CVS tags: ntddk-nov-1993, HEAD
Microsoft Windows NT Build 511 (DDK SDK) 11-01-1993

/******************************************************************************
 *
 *  S3 Bank Manager
 *
 * Copyright (c) 1992 Microsoft Corporation
 *****************************************************************************/

#include "driver.h"

// Bank select forward prototype.

VOID vSetS3Bank(PPDEV ppdev, UINT iBank);

/******************************************************************************
 * bBankInit - Initialize the bank manager.
 *
 *  Setup the ppdev->arclBanks Array.  Since this driver is chip specific,
 *  we can take a number of short cuts.  We know there will always
 *  be 1 meg of memory on the board, and there will only be 1 64K R/W
 *  bank.
 *
 *****************************************************************************/
BOOL bBankInit(
    PPDEV ppdev,
    BOOL fFirstTime)
{
    INT     i;
    BYTE    jMemCfg;

    DISPDBG((3, "S3.DLL: bBankInit - Entry\n"));

    if (fFirstTime)
    {
        ppdev->BankSize     = MEMORY_APERTURE_SIZE;
        ppdev->ScansPerBank = ppdev->BankSize / ppdev->cxMaxRam;
        ppdev->MaxBanks     = ppdev->cyMaxRam / ppdev->ScansPerBank;

        ppdev->prclBanks = LocalAlloc(LPTR, ppdev->MaxBanks * sizeof (RECT));
        if (ppdev->prclBanks == NULL)
        {
            DISPDBG((0, "S3.DLL!bBankInit -  LocalAlloc (prclBanks) failed \n"));
            EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
            return (FALSE);
        }

        ppdev->pBanks = LocalAlloc(LPTR, ppdev->MaxBanks * sizeof (BANK));
        if (ppdev->pBanks == NULL)
        {
            DISPDBG((0, "S3.DLL!bBankInit -  LocalAlloc (pBanks) failed \n"));
            EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
            return (FALSE);
        }

        // Note: We only care about scans for the S3 chip.  So don't
        // bother initializing the left and right sides of the rectangle.

        for (i = 0; i < ppdev->MaxBanks; i++) {
            ppdev->prclBanks[i].top    = i * ppdev->ScansPerBank;
            ppdev->prclBanks[i].bottom = ppdev->prclBanks[i].top + ppdev->ScansPerBank;
        }
    }

    // Unlock some of the S3 registers.

    OUTPW (CRTC_INDEX, ((REG_UNLOCK_1 << 8) | S3R8));

    // Enable the Memory Aperture.

    OUTP(CRTC_INDEX, S3R1);
    jMemCfg = INP(CRTC_DATA);
    jMemCfg |= CPUA_BASE;
    OUTP(CRTC_DATA, jMemCfg);

    // Get the initial value of S3R5 and save it away.
    // This will prevent reading the Aperature control register
    // each time we want to set the bank.

    OUTP(CRTC_INDEX, S3R5);
    ppdev->jS3R5 = INP(CRTC_DATA);
    ppdev->jS3R5 &= 0xF0;                 // Just mask for the bits we want.

    return(TRUE);
}

/******************************************************************************
 * bBankEnumStart - Start the bank enumeration.
 *
 *  Save the original values for pvScan0 and rclBounds (The start of the
 *  engine managed bitmap and the clipping bounding rectangle.)
 *
 *  Setup all the banks to enumerate in the ppdev->pBanks array.
 *  Setup the first bank to enumerate.
 *
 *  Entry:  prclScan->bottom - Ptr to the top (first) scan to render (inclusive)
 *          prclScan->top    - Ptr to the bottom (last) scan to render (inclusive)
 *          pso              - The surface object.
 *          pco              - The clipping object.
 *
 *  Exit:   TRUE             - if any rendering needs to be done.
 *          FALSE            - if there is nothing to render, (i.e. the object
 *                             is completely clipped out.)
 *          prclScan->bottom - The Top Scan to render into.
 *          prclScan->top    - The Bottom Scan to render into.
 *
 *****************************************************************************/
BOOL bBankEnumStart(
    PPDEV ppdev,
    PRECTL prclScans,
    SURFOBJ *pso,
    CLIPOBJ *pco)
{
    LONG    TopScan, BottomScan, BankBottom;
    PBYTE   pbScan0;
    INT     i, iFirstBank, iLastBank;

    DISPDBG((3, "S3.DLL: bBankEnumStart - Entry\n"));

    // Save the original pvScan0 and the ClipObj's rclBounds.

    ppdev->pvOrgScan0      = pso->pvScan0;
    ppdev->rclOrgBounds    = pco->rclBounds;
    ppdev->iOrgDComplexity = pco->iDComplexity;
    ppdev->fjOptions       = pco->fjOptions;

    // Set the flag in the clip object to tell the engine to forcible
    // clip to the rclBounds of the clip object.

    pco->fjOptions |= OC_BANK_CLIP;

    // If the clipping is not trivial, do an intersection of the
    // top & bottom scans with the clipping bounds.

    if (pco->iDComplexity != DC_TRIVIAL)
    {
        TopScan    = max (pco->rclBounds.top, prclScans->top);
        BottomScan = min (pco->rclBounds.bottom, prclScans->bottom);
    }
    else
    {
        TopScan    = prclScans->top;
        BottomScan = prclScans->bottom;
    }

    // Init the variables used to set up the banks.

    iLastBank = -1;
    ppdev->cBanks    = 0;
    ppdev->iBank     = 0;
    pbScan0   = (PBYTE) pso->pvScan0;

    // Find the bank that contains the top scan (the first bank).

    for (i = 0; i < ppdev->MaxBanks; i++)
    {
        BankBottom = ppdev->prclBanks[i].bottom;
        if (BankBottom > TopScan)
        {
            // The Top scan is within this bank,

            iFirstBank = i;

            // Set up the bank entry.

            ppdev->pBanks[ppdev->iBank].pvScan0     = pbScan0 - (i * ppdev->BankSize);
            ppdev->pBanks[ppdev->iBank].Bank        = i;
            ppdev->pBanks[ppdev->iBank].rclClip.top = TopScan;

            if (BankBottom < BottomScan)
            {
                ppdev->pBanks[ppdev->iBank].rclClip.bottom = BankBottom;
            }
            else
            {
                ppdev->pBanks[ppdev->iBank].rclClip.bottom = BottomScan;
                iLastBank = iFirstBank;
            }

            // Set the left and right bounds of the bank clip rect.

            ppdev->pBanks[ppdev->iBank].rclClip.left  = pco->rclBounds.left;
            ppdev->pBanks[ppdev->iBank].rclClip.right = pco->rclBounds.right;

            // Bump bank array index to next entry and the bank
            // count.

            ppdev->iBank++;
            ppdev->cBanks++;

            // Since we found the first bank, bail out of this loop.

            break;

        }
    }

    if (i == ppdev->MaxBanks) {

        RIP("S3.DLL: bBankEnumStart - error \n");
        return FALSE;
    }

    if (iLastBank != iFirstBank)
    {
        // Set the last bank to the first bank in case there are no
        // middle banks.

        iLastBank = iFirstBank;

        // Take care of all the middle banks.

        for (i = iFirstBank+1; i < ppdev->MaxBanks; i++)
        {
            if (ppdev->prclBanks[i].bottom < BottomScan)
            {
                // This bank is completely within the rendering rectangle.

                ppdev->pBanks[ppdev->iBank].pvScan0        = pbScan0 - (i * ppdev->BankSize);
                ppdev->pBanks[ppdev->iBank].Bank           = i;
                ppdev->pBanks[ppdev->iBank].rclClip.top    = ppdev->prclBanks[i].top;
                ppdev->pBanks[ppdev->iBank].rclClip.bottom = ppdev->prclBanks[i].bottom;

                // Set the left and right bounds of the bank clip rect.

                ppdev->pBanks[ppdev->iBank].rclClip.left  = pco->rclBounds.left;
                ppdev->pBanks[ppdev->iBank].rclClip.right = pco->rclBounds.right;

                // Bump bank array index to next entry and the bank
                // count.

                ppdev->iBank++;
                ppdev->cBanks++;

                iLastBank = i;
            }
            else
            {
                // The bottom of the bank we're currently "looking" at is
                // below (greater in value) than the bottom of the rectangle
                // were rendering, so there we're done looking at the middle
                // banks.

                break;
            }
        }

        // Now take care of the last bank.

        iLastBank++;

        if (ppdev->prclBanks[iLastBank].top < BottomScan)
        {
            ppdev->pBanks[ppdev->iBank].pvScan0        = pbScan0 - (iLastBank * ppdev->BankSize);
            ppdev->pBanks[ppdev->iBank].Bank           = iLastBank;

            ppdev->pBanks[ppdev->iBank].rclClip.top    = ppdev->prclBanks[iLastBank].top;
            ppdev->pBanks[ppdev->iBank].rclClip.bottom = BottomScan;

            ppdev->pBanks[ppdev->iBank].rclClip.left   = pco->rclBounds.left;
            ppdev->pBanks[ppdev->iBank].rclClip.right  = pco->rclBounds.right;

            ppdev->cBanks++;

        }
    }

    // We need to make sure the clipping level is at least DC_RECT.
    // Some code in the engine (like EngCopybits) will ignore the
    // clip rectangle entirely if the level is DC_TRIVIAL.

    if (pco->iDComplexity == DC_TRIVIAL)
        pco->iDComplexity = DC_RECT;

    // Now take care of setting the first bank

    ppdev->iBank = 1;                     // set the next bank index
    ppdev->cBanks--;                      // set # of remaining banks

    // Set the top and bottom scans for the caller

    prclScans->top    = ppdev->pBanks[0].rclClip.top;     // set top scan.
    prclScans->bottom = ppdev->pBanks[0].rclClip.bottom;  // set bottom scan.

    // Set the S3 chip.

    vSetS3Bank(ppdev, ppdev->pBanks[0].Bank);

    // Set the clip rectangle for the engine.

    pco->rclBounds = ppdev->pBanks[0].rclClip;

    // Set pvScan0 for the engine.

    pso->pvScan0 = ppdev->pBanks[0].pvScan0;

    ENABLE_DIRECT_ACCESS;

    return (TRUE);
}

/******************************************************************************
 * bSrcBankEnumStart - Start the bank enumeration when the screen is the
 *                     source
 *
 *  Save the original values for pvScan0 and rclBounds (The start of the
 *  engine managed bitmap and the clipping bounding rectangle.)
 *
 *  Setup all the banks to enumerate in the ppdev->pBanks array.
 *  Setup the first bank to enumerate.
 *
 *  Entry:  prclScan->bottom - Ptr to the top (first) scan to render (inclusive)
 *          prclScan->top    - Ptr to the bottom (last) scan to render (inclusive)
 *          pso              - The surface object.
 *          pco              - The clipping object.
 *
 *  Exit:   TRUE             - if any rendering needs to be done.
 *          FALSE            - if there is nothing to render, (i.e. the object
 *                             is completely clipped out.)
 *          prclScan->bottom - The Top Scan to render into.
 *          prclScan->top    - The Bottom Scan to render into.
 *
 * NOTE: This routine is a little trickier than bBankEnumStart.  We make GDI
 * read only the current bank by altering the CLIPOBJ before passing the
 * call back to GDI.  The problem here is that the CLIPOBJ applies only to the
 * destination, but for this case it's the screen that is the source.  So we
 * have to adjust for this accordingly.
 *
 *****************************************************************************/
BOOL bSrcBankEnumStart(
    PPDEV ppdev,
    PRECTL prclScans,
    SURFOBJ *pso,
    CLIPOBJ *pco,
    PRECTL  prclDest)
{
    LONG    TopScan, BottomScan, BankBottom;
    PBYTE   pbScan0;
    INT     i, iFirstBank, iLastBank, cyFirstBank, cyMiddleBanks;
    RECTL   rclBounds;

    DISPDBG((3, "S3.DLL: bSrcBankEnumStart - Entry\n"));

    // Save the original pvScan0 and the ClipObj's rclBounds.

    ppdev->pvOrgScan0      = pso->pvScan0;
    ppdev->rclOrgBounds    = pco->rclBounds;
    ppdev->iOrgDComplexity = pco->iDComplexity;
    ppdev->fjOptions       = pco->fjOptions;

    // If the clipping is not trivial, do an intersection of the
    // Set the flag in the clip object to tell the engine to forcible
    // clip to the rclBounds of the clip object.

    pco->fjOptions |= OC_BANK_CLIP;

    // top & bottom scans with the clipping bounds.

    // NOTE: Since the Scans rectangle and the clipping rectangle
    //       refer to two different surfaces, we will always use the
    //       the Scans rectangle to determine the bank(s) we need to
    //       enumerate.

    // rclBounds keeps track of the y-extents of the destination, and is
    // calculated from the intersection of the destination rectangle
    // and the CLIPOBJ's bounds:

    if (pco->iDComplexity != DC_TRIVIAL)
    {
        rclBounds.top    = max(prclDest->top,    pco->rclBounds.top);
        rclBounds.bottom = min(prclDest->bottom, pco->rclBounds.bottom);
    }
    else
    {
        rclBounds.top    = prclDest->top;
        rclBounds.bottom = prclDest->bottom;
    }

    // TopScan and BottomScan keep track of the corresponding y-extents of
    // the source:

    TopScan    = prclScans->top    + (rclBounds.top    - prclDest->top);
    BottomScan = prclScans->bottom + (rclBounds.bottom - prclDest->bottom);

    // Init the variables used to set up the banks.

    iLastBank     = -1;
    ppdev->cBanks = 0;
    ppdev->iBank  = 0;
    pbScan0       = (PBYTE) pso->pvScan0;

    // Find the bank that contains the top scan (the first bank).

    for (i = 0; i < ppdev->MaxBanks; i++)
    {
        BankBottom = ppdev->prclBanks[i].bottom;
        if (BankBottom > TopScan)
        {
            // The Top scan is within this bank,

            iFirstBank = i;

            // Set up the bank entry.

            ppdev->pBanks[ppdev->iBank].pvScan0     = pbScan0 - (i * ppdev->BankSize);
            ppdev->pBanks[ppdev->iBank].Bank        = i;
            ppdev->pBanks[ppdev->iBank].rclClip.top = rclBounds.top;

            // Take care of the case where the entire operation
            // fits within one bank.

            if (BankBottom < BottomScan)
            {
                // The operation spans more than this one bank.

                cyFirstBank = BankBottom - TopScan;
                ppdev->pBanks[ppdev->iBank].rclClip.bottom = rclBounds.top + cyFirstBank;
            }
            else
            {
                // The operation is completel contained with in this
                // single bank.

                ppdev->pBanks[ppdev->iBank].rclClip.bottom = rclBounds.bottom;
                iLastBank = iFirstBank;
            }

            // Set the left and right bounds of the bank clip rect.

            ppdev->pBanks[ppdev->iBank].rclClip.left  = pco->rclBounds.left;
            ppdev->pBanks[ppdev->iBank].rclClip.right = pco->rclBounds.right;

            // Bump bank array index to next entry and the bank
            // count.

            ppdev->iBank++;
            ppdev->cBanks++;

            // Since we found the first bank, bail out of this loop.

            break;

        }
    }

    if (i == ppdev->MaxBanks) {

        RIP("S3.DLL: bSrcBankEnumStart - error \n");
        return FALSE;
    }

    if (iLastBank != iFirstBank)
    {
        // Set the last bank to the first bank in case there are no
        // middle banks.

        iLastBank = iFirstBank;

        // Take care of all the middle banks.
        // Update rclBounds for this bank.

        rclBounds.top += cyFirstBank;

        cyMiddleBanks = ppdev->ScansPerBank;
        rclBounds.bottom = rclBounds.top + cyMiddleBanks;

        for (i = iFirstBank+1; i < ppdev->MaxBanks; i++)
        {
            if (ppdev->prclBanks[i].bottom < BottomScan)
            {
                // This bank is completely within the rendering rectangle.

                ppdev->pBanks[ppdev->iBank].pvScan0        = pbScan0 - (i * ppdev->BankSize);
                ppdev->pBanks[ppdev->iBank].Bank           = i;

                ppdev->pBanks[ppdev->iBank].rclClip.top    = rclBounds.top;
                ppdev->pBanks[ppdev->iBank].rclClip.bottom = rclBounds.bottom;

                // Set the left and right bounds of the bank clip rect.

                ppdev->pBanks[ppdev->iBank].rclClip.left  = pco->rclBounds.left;
                ppdev->pBanks[ppdev->iBank].rclClip.right = pco->rclBounds.right;

                // Update for the next bank bounds.

                rclBounds.top += cyMiddleBanks;

                rclBounds.bottom = rclBounds.top + cyMiddleBanks;

                // Bump bank array index to next entry and the bank
                // count.

                ppdev->iBank++;
                ppdev->cBanks++;

                iLastBank = i;

            }
        }

        // Now take care of the last bank.

        iLastBank++;

        if (ppdev->prclBanks[iLastBank].top < BottomScan)
        {
            ppdev->pBanks[ppdev->iBank].pvScan0        = pbScan0 - (iLastBank * ppdev->BankSize);
            ppdev->pBanks[ppdev->iBank].Bank           = iLastBank;

            ppdev->pBanks[ppdev->iBank].rclClip.top    = rclBounds.top;
            ppdev->pBanks[ppdev->iBank].rclClip.bottom = rclBounds.bottom;

            ppdev->pBanks[ppdev->iBank].rclClip.left   = pco->rclBounds.left;
            ppdev->pBanks[ppdev->iBank].rclClip.right  = pco->rclBounds.right;

            ppdev->cBanks++;

        }
    }

    // We need to make sure the clipping level is at least DC_RECT.
    // Some code in the engine (like EngCopybits) will ignore the
    // clip rectangle entirely if the level is DC_TRIVIAL.

    if (pco->iDComplexity == DC_TRIVIAL)
        pco->iDComplexity = DC_RECT;

    // Now take care of setting the first bank

    ppdev->iBank = 1;                     // set the next bank index
    ppdev->cBanks--;                      // set # of remaining banks

    // Set the top and bottom scans for the caller

    prclScans->top    = ppdev->pBanks[0].rclClip.top;     // set top scan.
    prclScans->bottom = ppdev->pBanks[0].rclClip.bottom;  // set bottom scan.

    // Set the S3 chip.

    vSetS3Bank(ppdev, ppdev->pBanks[0].Bank);

    // Set the clip rectangle for the engine.

    pco->rclBounds = ppdev->pBanks[0].rclClip;

    // Set pvScan0 for the engine.

    pso->pvScan0 = ppdev->pBanks[0].pvScan0;

    ENABLE_DIRECT_ACCESS;

    return (TRUE);
}

/******************************************************************************
 * bBankEnum - Enumerate the next bank.
 *
 *  Just enumerate the next bank.  pvScan0, the clipping Rect, and the
 *  chip are all set up for this bank.
 *
 *  Entry:  none
 *
 *  Exit:   TRUE        - if this bank needs any rendering.
 *          FALSE       - if there is nothing to render.
 *
 *          prclScans   - The Scans to render into.
 *
 ******************************************************************************/
BOOL bBankEnum(
    PPDEV ppdev,
    PRECTL prclScans,
    SURFOBJ *pso,
    CLIPOBJ *pco)
{
    DISPDBG((3, "S3.DLL: bBankEnum - Entry\n"));

    if (ppdev->cBanks == 0)
        return (FALSE);

    // Set the top and bottom scans for the caller

    prclScans->top    = ppdev->pBanks[ppdev->iBank].rclClip.top;     // set top scan.
    prclScans->bottom = ppdev->pBanks[ppdev->iBank].rclClip.bottom;  // set bottom scan.

    // Set the S3 chip.

    vSetS3Bank(ppdev, ppdev->pBanks[ppdev->iBank].Bank);

    // Set the clip rectangle for the engine.

    pco->rclBounds = ppdev->pBanks[ppdev->iBank].rclClip;

    // Set pvScan0 for the engine.

    pso->pvScan0 = ppdev->pBanks[ppdev->iBank].pvScan0;

    // Update the bank index and bank count.

    ppdev->cBanks--;
    ppdev->iBank++;

    return (TRUE);
}

/******************************************************************************
 * bBankEnumEnd - Finish the bank enumeration.
 *
 *  Cleanup from the enumeration.  This restores the original pvScan0 and
 *  ClipRectangle.
 *
 ******************************************************************************/
BOOL bBankEnumEnd(
    PPDEV ppdev,
    SURFOBJ *pso,
    CLIPOBJ *pco)
{
    DISPDBG((3, "S3.DLL: bBankEnumEnd - Entry\n"));

    pso->pvScan0      = ppdev->pvOrgScan0;
    pco->rclBounds    = ppdev->rclOrgBounds;
    pco->iDComplexity = ppdev->iOrgDComplexity;
    pco->fjOptions    = ppdev->fjOptions;

    ENABLE_S3_ENGINE;

    return (TRUE);
}




/******************************************************************************
 * vSetS3Bank - Set the bank on the S3 chip.
 ******************************************************************************/
VOID vSetS3Bank(
    PPDEV ppdev,
    UINT iBank)
{

    TEST_928("S3.DLL!vSetS3Bank - pre bank switch 928 failure\n");

    // Set the bank

    OUTPW1 (CRTC_INDEX, (((ppdev->jS3R5 | (0x0F & iBank)) << 8) | S3R5));

    if (ppdev->bNewBankControl == TRUE)
    {
        OUTP1 (CRTC_INDEX, EX_SCTL_2);
        OUTP1 (CRTC_DATA, ppdev->ExtSysCtl2 | ((0x30 & iBank) >> 2));
    }

    // CHIPBUG.
    // Anil said I should read this back.

    INP1(CRTC_DATA);

    TEST_928("S3.DLL!vSetS3Bank - post bank switch 928 failure\n");

}

unix.superglobalmegacorp.com

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