/***************************************************************************
*
*                ******************************************
*                * Copyright (c) 1995, Cirrus Logic, Inc. *
*                *            All Rights Reserved         *
*                ******************************************
*
* PROJECT:	Laguna I (CL-GD5462) - 
*
* FILE:		pointer.c
*
* AUTHOR:   Benny Ng
*
* DESCRIPTION:
*           This module contains the SW & HW curosr support for the
*           Laguna NT driver.
*
* MODULES:
*           DrvMovePointer()
*           DrvSetPointerShape()
*
* REVISION HISTORY:
*   6/20/95     Benny Ng      Initial version
*
* $Log:   X:/log/laguna/nt35/displays/cl546x/POINTER.C  $
* 
*    Rev 1.39   Mar 04 1998 15:30:24   frido
* Added new shadow macros.
* 
*    Rev 1.38   Jan 19 1998 10:26:26   frido
* HP#86 (no PDR yet). Removed hardware cursor for 1600x1200 >=65Hz.
* 
*    Rev 1.37   Nov 03 1997 11:30:16   frido
* Added REQUIRE macros.
* 
*    Rev 1.36   23 Sep 1997 10:48:22   bennyn
* Not use HW cursor if the resolution is below 640x480
* 
*    Rev 1.35   11 Jun 1997 15:13:14   bennyn
* Fixed PDR 9747 Punt to SW cursor in 1600x1200x8 & x16 at 65,70,75 Hz
* 
*    Rev 1.34   11 Jun 1997 14:02:30   bennyn
* Fixed PDR 9741 (animated cursor turns back)
* 
*    Rev 1.33   28 May 1997 14:17:58   bennyn
* Fixed PDR 9741 and eliminated dead code
* 
*    Rev 1.32   01 May 1997 15:02:12   bennyn
* Punt the cursor if it is in interlace modes
* 
*    Rev 1.31   09 Apr 1997 10:53:36   SueS
* Changed type of pointer_switch to eliminate compiler warning.
* 
*    Rev 1.30   08 Apr 1997 15:22:50   SueS
* Don't use color for monochrome animated cursors - otherwise we'll 
* reference a NULL pointer.
* 
*    Rev 1.29   07 Apr 1997 12:44:50   BENNYN
* Added the checking ptrmaskhandle equal to NULL
* 
*    Rev 1.28   02 Apr 1997 14:24:14   noelv
* NT 35.1 wass accessing a NULL pointer in DrvMovePointer
* Removed SW cursor and chainblt cursor code 
* 
*    Rev 1.27   21 Mar 1997 13:37:44   noelv
* 
* Combined do_flag and sw_test_flag into pointer_switch
* 
*    Rev 1.26   03 Feb 1997 13:35:22   bennyn
* Modified the 5465 cursor algorithm
* 
*    Rev 1.25   30 Jan 1997 17:15:02   bennyn
* Added cursor algorithm for 5465
* 
*    Rev 1.24   17 Dec 1996 17:01:10   SueS
* Added test for writing to log file based on cursor at (0,0).
* 
*    Rev 1.23   10 Dec 1996 14:32:46   bennyn
* 
* Fixed cursor mask from device bitmap problem
* 
*    Rev 1.22   26 Nov 1996 10:43:04   SueS
* Changed WriteLogFile parameters for buffering.
* 
*    Rev 1.21   13 Nov 1996 17:00:52   SueS
* Changed WriteFile calls to WriteLogFile.
* 
*    Rev 1.20   01 Nov 1996 09:26:46   BENNYN
* 
* Cleanup unused code
* 
*    Rev 1.19   23 Oct 1996 14:44:44   BENNYN
* 
* Fixed the YUV cursor problems
* 
*    Rev 1.18   06 Sep 1996 09:07:02   noelv
* 
* Cleaned up NULL driver code.
* 
*    Rev 1.17   26 Aug 1996 17:35:08   bennyn
* 
* Restore the changes for the losed version
* 
*    Rev 1.16   20 Aug 1996 11:04:20   noelv
* Bugfix release from Frido 8-19-96
* 
*    Rev 1.3   17 Aug 1996 19:39:20   frido
* Fixed DirectDraw cursor problem.
* 
*    Rev 1.2   17 Aug 1996 13:34:56   frido
* New release from Bellevue.
* 
*    Rev 1.1   15 Aug 1996 11:40:18   frido
* Added precompiled header.
* 
*    Rev 1.0   14 Aug 1996 17:16:30   frido
* Initial revision.
* 
*    Rev 1.13   25 Jul 1996 15:56:00   bennyn
* 
* Modified to support DirectDraw
* 
*    Rev 1.12   18 Jun 1996 12:44:18   noelv
* Fixed the way interleave is calculated.
* 
*    Rev 1.11   28 May 1996 15:11:28   noelv
* Updated data logging.
* 
*    Rev 1.10   01 May 1996 12:23:30   bennyn
* 
*    Rev 1.9   01 May 1996 12:05:36   bennyn
* Fixed resolution change bug for NT4.0
* 
*    Rev 1.8   01 May 1996 11:00:48   bennyn
* 
* Modified for NT4.0
* 
*    Rev 1.7   04 Apr 1996 13:20:24   noelv
* Frido release 26
 * 
 *    Rev 1.4   28 Mar 1996 20:22:28   frido
 * Removed warning messages from new Bellevue release.
* 
*    Rev 1.6   25 Mar 1996 18:55:30   noelv
* Fixed bouncing screeen when cursor is disabled.
* 
*    Rev 1.5   08 Mar 1996 17:27:38   noelv
* 
* Added NULL_POINTER flag
* 
*    Rev 1.4   07 Mar 1996 18:22:46   bennyn
* 
* Removed read/modify/write on CONTROL reg
* 
*    Rev 1.3   05 Mar 1996 11:58:26   noelv
* Frido version 19
 * 
 *    Rev 1.1   20 Jan 1996 01:22:00   frido
 *  
* 
*    Rev 1.10   15 Jan 1996 16:59:58   NOELV
* AB workaround reductions
* 
*    Rev 1.9   11 Jan 1996 09:22:04   NOELV
* Removed al 16 bit writes to X,Y,and BLTEXT registers.
* 
*    Rev 1.8   10 Jan 1996 16:20:56   NOELV
* Added increased logging capabilities.
* Added null driver capabilities.
* 
*    Rev 1.7   29 Nov 1995 12:11:42   noelv
* 
* Coded a workaround for HW bug.  The screen corrupts sometimes when the curs
* I changed the code to turn the cursor off as little as possible.
* 
*    Rev 1.6   29 Sep 1995 10:26:20   bennyn
* 
* Punt the cursor to GDI for 1600x1200 modes
* 
*    Rev 1.5   29 Sep 1995 09:54:58   bennyn
* 
*    Rev 1.4   27 Sep 1995 16:45:40   bennyn
* Fixed the HW cursor AND mask
* 
*    Rev 1.3   26 Sep 1995 16:27:50   bennyn
* 
*    Rev 1.2   26 Sep 1995 09:35:16   bennyn
* Enable HW cursor
* 
*    Rev 1.1   21 Aug 1995 13:52:16   NOELV
* Initial port to real hardware.
* Converted all 32 bit register writes to 2 16 bit regiser writes.
* 
*    Rev 1.0   25 Jul 1995 11:19:28   NOELV
* Initial revision.
* 
*    Rev 1.6   06 Jul 1995 09:57:10   BENNYN
* 
* Fixed the problem switching between full-screen & Windowed DOS box
* 
*    Rev 1.5   29 Jun 1995 09:50:54   BENNYN
* Fixed the unsupport cursor request problem
* 
*    Rev 1.4   29 Jun 1995 09:01:30   BENNYN
* 
*    Rev 1.3   28 Jun 1995 11:13:32   BENNYN
* Fixed 16-bit/pixel problem
* 
*    Rev 1.2   22 Jun 1995 13:33:32   BENNYN
* 
* Added SW cursor auto BLT
* 
*    Rev 1.1   20 Jun 1995 16:09:30   BENNYN
* 
*
****************************************************************************
****************************************************************************/

/*----------------------------- INCLUDES ----------------------------------*/
#include "precomp.h"

/*----------------------------- DEFINES -----------------------------------*/
//#define DBGBRK
//#define DBGDISP
#define CURSOR_DBG_LEVEL 1

#define  MAX_CNT           0x7FFF
#define  BLT_FLAG_BIT      0x2L
#define  BYTES_PER_TILE    0x800  // 2048


/*--------------------- STATIC FUNCTION PROTOTYPES ------------------------*/

/*--------------------------- ENUMERATIONS --------------------------------*/

/*----------------------------- TYPEDEFS ----------------------------------*/
typedef union _HOST_DATA {
    BYTE    bData[4];
    DWORD   dwData;
} HOST_DATA;


/*-------------------------- STATIC VARIABLES -----------------------------*/

/*-------------------------- GLOBAL FUNCTIONS -----------------------------*/
VOID CopyLgHWPtrMaskData(PPDEV ppdev,
                         LONG  Ycord,
                         LONG  lSrcDelta,
                         LONG  cy,
                         ULONG tileszx,
                         BYTE  *pANDSrcScan,
                         BYTE  *pXORSrcScan);

ULONG ConvertMaskBufToLinearAddr(PPDEV ppdev);

VOID RestoreSaveShowCursor(PPDEV ppdev,
                           LONG  x,
                           LONG  y);

#if POINTER_SWITCH_ENABLED
    int pointer_switch=0;
#endif

#if LOG_QFREE
    unsigned long QfreeData[32];
#endif



/****************************************************************************
* FUNCTION NAME: InitPointerHW()
*
* DESCRIPTION:   Initialization the cursor palette colors.
*
****************************************************************************/
VOID InitPointerHW (PPDEV ppdev)
{
  ULONG   ultmp;

  // Enable HW cursor color access
  ultmp = LLDR_SZ (grPalette_State);
  ultmp |= 0x8;
  LL8 (grPalette_State, ultmp);

  // Write HW cursor BK & FG color
  ultmp = 0;
  LL8 (grPalette_Write_Address, ultmp);
  LL8 (grPalette_Data, ultmp);
  LL8 (grPalette_Data, ultmp);
  LL8 (grPalette_Data, ultmp);
  
  ultmp = 0xF;
  LL8 (grPalette_Write_Address, ultmp);

  ultmp = 0xFF;
  LL8 (grPalette_Data, ultmp);
  LL8 (grPalette_Data, ultmp);
  LL8 (grPalette_Data, ultmp);

  // Disable HW cursor color access
  ultmp = LLDR_SZ (grPalette_State);
  ultmp &= 0xFFF7;
  LL8 (grPalette_State, ultmp);
}



/****************************************************************************
* FUNCTION NAME: InitPointer()
*
* DESCRIPTION:   Initialization the variables used by the pointer.
*
* REVISION HISTORY:
*   6/20/95     Benny Ng      Initial version
****************************************************************************/
VOID InitPointer(PPDEV ppdev)
{
  ULONG   ultmp;
  SIZEL   reqsz;

  ppdev->PointerUsage = HW_CURSOR;
  DISPDBG((CURSOR_DBG_LEVEL, "HW cursor\n"));

  ppdev->bYUVuseSWPtr = FALSE;
  ppdev->PtrImageHandle = NULL;
  ppdev->PtrABltHandle = NULL;

  // Get the current tile size
  if (ppdev->lTileSize == (LONG) 128)
  {
     reqsz.cx = 128;  
     reqsz.cy = 8;
  }
  else if (ppdev->lTileSize == (LONG) 256)
  {
     reqsz.cx = 256;
     reqsz.cy = 4;
  }
  else
  {
     reqsz.cx = 1024;
     reqsz.cy = 1;
  };

  InitPointerHW (ppdev);

  // Allocate the mask buffer from offscreen memory
  DISPDBG((CURSOR_DBG_LEVEL, "Allocating Pointer Mask\n"));
  ppdev->PtrMaskHandle = AllocOffScnMem(ppdev, &reqsz, 0, NULL);

#ifdef WINNT_VER40
  ppdev->CShsem = NULL;
#endif
}



/****************************************************************************
* FUNCTION NAME: DrvMovePointer()
*
* DESCRIPTION:   This function Moves the hardware pointer to a new position.
*
* REVISION HISTORY:
*   6/20/95     Benny Ng      Initial version
****************************************************************************/
VOID DrvMovePointer(SURFOBJ *pso,
                    LONG     x,
                    LONG     y,
                    RECTL   *prcl)
{
    LONG  adjx, adjy;
    LONG  delaycnt = 0;

    PPDEV ppdev = (PPDEV) pso->dhpdev;

    if (x==0 && y==0)
    {
        // 
        // This isn't used in the released code.  This is test code for setting
        // the sw_test_flag to different values by pointing the cursor to 
        // 'special' places.  Used to turn different test features on and off.
        //
        #if (POINTER_SWITCH_ENABLED)
       	    if (pointer_switch)
                pointer_switch = 0;
            else
                pointer_switch = 1;
        #endif

   	    #if ENABLE_LOG_SWITCH && POINTER_SWITCH_ENABLED
       	    if (pointer_switch)
            {
                CreateLogFile(ppdev->hDriver, &ppdev->TxtBuffIndex);
                ppdev->pmfile = ppdev->hDriver;   // handle to the miniport
                lg_i = sprintf(lg_buf, "Log file opened\r\n");
                WriteLogFile(ppdev->pmfile, lg_buf, lg_i, ppdev->TxtBuff, &ppdev->TxtBuffIndex);

            }
            else
   	           CloseLogFile(ppdev->pmfile, ppdev->TxtBuff, &ppdev->TxtBuffIndex);
   	    #endif

        #if NULL_HW
            //
            // Enables and disables the "infinitly fast hardware" feature.
            // then "on" all register writes go to a chunk of blank memory 
            // on the host.  Register reads proceed normally.
            //
    	    if (ppdev->pLgREGS == ppdev->pLgREGS_real)
	        	ppdev->pLgREGS = (GAR *)ppdev->buffer;
	        else
    	    	ppdev->pLgREGS = ppdev->pLgREGS_real;
        #endif

        #if LOG_QFREE
        {
            int i;
            
            DISPDBG((CURSOR_DBG_LEVEL,"Dumping QFREE log.\n"));
            lg_i = sprintf(lg_buf,"\r\n\r\n");
            WriteLogFile(ppdev->pmfile, lg_buf, lg_i, ppdev->TxtBuff, &ppdev->TxtBuffIndex);

            for (i=0; i<32; ++i)
            {
                lg_i = sprintf(lg_buf,"QFREE %d: %d times.\r\n", i, QfreeData[i]);
                WriteLogFile(ppdev->pmfile, lg_buf, lg_i, ppdev->TxtBuff, &ppdev->TxtBuffIndex);
                QfreeData[i] = 0;
            }
        }
        #endif    
   	} // End if x==0 and y==0


    #if LOG_CALLS
        #if ENABLE_LOG_SWITCH
        if (pointer_switch)
        #endif
        {
            lg_i = sprintf(lg_buf,"DrvMovePointer: x=%d, y=%d \r\n", x, y);
            WriteLogFile(ppdev->pmfile, lg_buf, lg_i, ppdev->TxtBuff, &ppdev->TxtBuffIndex);
        }
    #endif


    #if NULL_POINTER
        if (pointer_switch)	return;
    #endif

    if ((ppdev->PointerUsage == DEF_CURSOR) ||
        (ppdev->PtrMaskHandle == NULL))
		return;

    adjx = x;
    adjy = y;

    // Check whether want to hide the pointer.
    if (x == -1)
    {
	    #if HW_PRESET_BUG
            LL16 (grCursor_X, (WORD)0xFFFF);
            LL16 (grCursor_Y, (WORD)0xFFFF);
 	    #else
        	// Disable the Hw cursor by clearing the hw cursor enable
            // bit in CURSOR_CONTROL reg
            ultmp = LLDR_SZ (grCursor_Control);
            if (ultmp & 1)
            {
                ultmp &= 0xFFFE;
                LL16 (grCursor_Control, ultmp);
            }
	    #endif
    }

    else if ((adjx >= 0) && (adjy >= 0))
    {
	    // Restore the current pointer area screen image from offscreen memory.
     	// Save the new pointer area screen image to offscreen memory.
     	// Show the curosr using both AND and XOR masks
     	RestoreSaveShowCursor(ppdev, adjx, adjy);

     	ppdev->PtrX = adjx;
     	ppdev->PtrY = adjy;

        if (prcl != NULL)
        {
           	prcl->left = ppdev->PtrX;
          	prcl->top  = ppdev->PtrY;
          	prcl->right  = prcl->left + ppdev->PtrSzX;
          	prcl->bottom = prcl->top  + ppdev->PtrSzY;

 	        ppdev->prcl.left = prcl->left;
    	    ppdev->prcl.top  = prcl->top;
    	    ppdev->prcl.right = prcl->right;
    	    ppdev->prcl.bottom = prcl->bottom;
        }
    }
    return;
}



/****************************************************************************
* FUNCTION NAME: DrvSetPointerShape()
*
* DESCRIPTION:   This function sets the new pointer shape.
*
* REVISION HISTORY:
*   6/20/95     Benny Ng      Initial version
****************************************************************************/
ULONG DrvSetPointerShape(SURFOBJ  *pso,
                         SURFOBJ  *psoMask,
                         SURFOBJ  *psoColor,
                         XLATEOBJ *pxlo,
                         LONG      xHot,
                         LONG      yHot,
                         LONG      x,
                         LONG      y,
                         RECTL    *prcl,
                         FLONG     fl)
{

  BOOL    bAnimatedCursor = FALSE;
  LONG    lSrcDelta;
  ULONG   retul;
  ULONG   cx, cy;
  LONG    bpp;
  SIZEL   tilesz;
  SIZEL   reqsz;
  BYTE    *pANDSrcScan;
  BYTE    *pXORSrcScan;
  LONG    Ycord;
  ULONG   curloc;
  ULONG   ultmp;
  PPDEV   ppdev = (PPDEV) pso->dhpdev;

    #if NULL_POINTER
        if (pointer_switch)
		return SPS_ACCEPT_NOEXCLUDE;
    #endif
   
    DISPDBG((CURSOR_DBG_LEVEL, "DrvSetPointerShape %d, x=%d, y=%d, xHot=%d, yHot=%d\n",
           ppdev->PointerUsage, x, y, xHot, yHot));

    // If no HW cursor mask buffer allocated from offscreen memory,
    // or If in intrelace mode, Use SW cursor
    // Use SW cursor
    if ((ppdev->PtrMaskHandle == NULL) || (ppdev->ulFreq < 50))
       return (SPS_DECLINE);

    // HW cursor bug in 1600x1200-8bpp & 16bpp with refresh rate 65,
    // 70 or 75Hz. Use SW cursor
    if ((ppdev->cxScreen == 1600) && (ppdev->cyScreen == 1200) &&
        ((ppdev->ulBitCount == 8) || (ppdev->ulBitCount == 16)))
    {
       if (ppdev->ulFreq >= 65)
          return (SPS_DECLINE);
    };

    // Don't use HW cursor if resolution below 640x480
    if ((ppdev->cxScreen < 640) || (ppdev->cyScreen < 480))
       return (SPS_DECLINE);

    // Get dimensions of the pointer
    cx = psoMask->sizlBitmap.cx ;
    cy = psoMask->sizlBitmap.cy >> 1;

    // Calculate bytes per pixel
    bpp = ppdev->iBytesPerPixel;

    // Get the current tile size
    if (ppdev->lTileSize == (LONG) 128)
    {
        tilesz.cx = 128;	
	    tilesz.cy = 16;
    }
    else if (ppdev->lTileSize == (LONG) 256)
    {
        tilesz.cx = 256;
	    tilesz.cy = 8;
    }
    else
    {
        tilesz.cx = 2048;
	    tilesz.cy = 1;
    };

    lSrcDelta = psoMask->lDelta;
    retul = SPS_ACCEPT_NOEXCLUDE; // We can still draw while HW cursor is on the screen.

    // Check whether we should let the GDI handle the pointer
    if ((ppdev->PointerUsage == DEF_CURSOR) ||
        (psoMask == (SURFOBJ *) NULL)       ||
        (cx > HW_POINTER_DIMENSION)         ||
        (cy > (HW_POINTER_DIMENSION - 1))   ||
        (psoColor != NULL)       ||
        (fl & SPS_ASYNCCHANGE)	|| // We can't change the cursor shape while drawing.
        (fl & SPS_ANIMATESTART)	|| // We don't do animated cursors
        (fl & SPS_ANIMATEUPDATE) || // We don't do animated cursors
        !(fl & SPS_CHANGE))
    {
        bAnimatedCursor = TRUE;

	    #if HW_PRESET_BUG
            LL16 (grCursor_X, (WORD)0xFFFF);
            LL16 (grCursor_Y, (WORD)0xFFFF);
	    #else
            // Disable the Hw cursor by clearing the hw cursor enable
            // bit in CURSOR_CONTROL reg
            ultmp = LLDR_SZ (grCursor_Control);
            if (ultmp & 1)
            {
                ultmp &= 0xFFFE;
                LL16 (grCursor_Control, ultmp);
            }
	    #endif
    };

    // Save the position informations
    //
    ppdev->PtrXHotSpot = xHot;
    ppdev->PtrYHotSpot = yHot;
    ppdev->PtrSzX = cx;
    ppdev->PtrSzY = cy;

    // Setup the AND and XOR mask data pointer
    pANDSrcScan = psoMask->pvScan0;
    pXORSrcScan = psoMask->pvScan0;
    pXORSrcScan += (cy * lSrcDelta);

    // If animated cursor generate the XOR mask from psoColor->pvScan0
    // data
    if ((bAnimatedCursor) && (psoColor != NULL))
    {
       PDSURF  pDSURF;
       POFMHDL pOFMHDL;
       SURFOBJ*  pDsurfSo;
       BYTE  XorMaskBuf[130];
       BYTE  *pColorSrcScan;
       BYTE  maskval;
       LONG  ii, jj, kk, mm;
       BOOL  bCalc;

       bCalc = FALSE;
       pColorSrcScan = NULL;
       if (psoColor->pvScan0 != NULL)
       {
          // From host memory
          pColorSrcScan = psoColor->pvScan0;
       }
       else
       {
          // From device bitmap
          pDSURF  = (DSURF *) psoColor->dhsurf;
          pDsurfSo = (SURFOBJ*) pDSURF->pso;

          if (pDsurfSo != NULL)
          {
             pColorSrcScan = pDsurfSo->pvScan0;
          }
          else
          {
             pOFMHDL = (OFMHDL *) pDSURF->pofm;
             if (pOFMHDL != NULL)
             {
                bCalc = TRUE;
                pColorSrcScan = (BYTE *)((pOFMHDL->aligned_y * ppdev->lDeltaScreen) +
                                          pOFMHDL->aligned_x + (ULONG) ppdev->pjScreen);
             };  // endif (pOFMHDL != NULL)
          };  // endif (pDsurfSo != NULL)
       };  // endif (psoColor->pvScan0 != NULL)

       if (pColorSrcScan != NULL)
       {
          mm = 0;
          for (ii=0; ii < 0x20; ii++)
          {
            for (jj=0; jj < 0x4; jj++)
            {
              maskval = 0;
              for (kk=0; kk < 0x8; kk++)
              {
                maskval = maskval << 1;
   
                if ((*pColorSrcScan & 1) != 0)
                   maskval |= 0x1;
   
                pColorSrcScan += ppdev->iBytesPerPixel;
   
              };  // endfor kk
   
              XorMaskBuf[mm++] = maskval;
   
            };  // endfor jj

            if (bCalc)
            {
               pColorSrcScan = (BYTE *)(((pOFMHDL->aligned_y+ii) * ppdev->lDeltaScreen) +
                                          pOFMHDL->aligned_x + (ULONG) ppdev->pjScreen);
            };

          };  // endfor ii

          pXORSrcScan = &XorMaskBuf[0];

       };  // endif (pColorSrcScan != NULL)
    };  // endif (bAnimatedCursor)

    // Set Laguna Command Control Register SWIZ_CNTL bit
    ppdev->grCONTROL |= SWIZ_CNTL;
    LL16(grCONTROL, ppdev->grCONTROL);

    // Setup the laguna registers for byte to byte BLT extents
	REQUIRE(6);
    LL_DRAWBLTDEF(0x102000CC, 0);
    LL_OP1 (0,0);
    Ycord = ppdev->PtrMaskHandle->aligned_y;
    LL_OP0_MONO (ppdev->PtrMaskHandle->aligned_x, Ycord);

    // Use the AND and XOR mask to create the mask buffer for Laguna HW.
    CopyLgHWPtrMaskData(ppdev, Ycord, lSrcDelta, cy, tilesz.cx, pANDSrcScan, pXORSrcScan);

    // Set the HW cursor mask location register
    curloc = ConvertMaskBufToLinearAddr(ppdev);
    curloc = (curloc >> 8) & 0xFFFC;
    LL16 (grCursor_Location, curloc);

    // Clear Laguna Command Control Register SWIZ_CNTL bit
    ppdev->grCONTROL = ppdev->grCONTROL & ~SWIZ_CNTL;
    LL16(grCONTROL, ppdev->grCONTROL);

    // Specific the exclude rectange
    if (prcl != NULL)
    {
       prcl->left = x - xHot;
       prcl->top  = y - yHot;
       prcl->right  = prcl->left + cx;
       prcl->bottom = prcl->top  + cy;

       ppdev->prcl.left = prcl->left;
       ppdev->prcl.top  = prcl->top;
       ppdev->prcl.right = prcl->right;
       ppdev->prcl.bottom = prcl->bottom;
    };

    if (bAnimatedCursor)
    {
        DISPDBG((CURSOR_DBG_LEVEL, "DrvSetPointerShape - SPS_DECLINE\n"));

        // Indicate use animiated cursor
        ppdev->bYUVuseSWPtr = TRUE;

        if (!ppdev->bYUVSurfaceOn)
            return (SPS_DECLINE);
    };

    if ((ppdev->bYUVuseSWPtr) && (x == -1) && (y == -1))
    {
	    #if HW_PRESET_BUG
            LL16 (grCursor_X, (WORD)0xFFFF);
            LL16 (grCursor_Y, (WORD)0xFFFF);
	    #else
            // Disable the Hw cursor by clearing the hw cursor enable
            // bit in CURSOR_CONTROL reg
            ultmp = LLDR_SZ (grCursor_Control);
            if (ultmp & 1)
            {
                ultmp &= 0xFFFE;
                LL16 (grCursor_Control, ultmp);
            }
	    #endif

       ppdev->bYUVuseSWPtr = FALSE;

       return (SPS_DECLINE);
    };

    // Enable the Hw cursor by setting the hw cursor enable
    // bit in CURSOR_CONTROL reg
    ultmp = LLDR_SZ (grCursor_Control);
    if ((ultmp & 1) == 0)
    {
       ultmp |= 0x0001;
       LL16 (grCursor_Control, ultmp);
    };

    // Indicate use HW cursor
    ppdev->bYUVuseSWPtr = FALSE;

    // Show the pointer by using the mask buffer
    DrvMovePointer(pso, x, y, prcl);

    return (retul);
}



/****************************************************************************
* FUNCTION NAME: CopyLgHWPtrMaskData()
*
* DESCRIPTION:   Using the AND & XOR source mask data to generate
*                a 64x64 bits pointer size mask buffer in the offscreen
*                memory for Laguna HW.
*
* REVISION HISTORY:
*   6/20/95     Benny Ng      Initial version
****************************************************************************/
VOID CopyLgHWPtrMaskData(PPDEV ppdev,
                         LONG  Ycord,
                         LONG  lSrcDelta,
                         LONG  cy,
                         ULONG tileszx,
                         BYTE  *pANDSrcScan,
                         BYTE  *pXORSrcScan)
{
  LONG       i, j, k;
  LONG       cnt;
  LONG       DWcnt;
  PDWORD     pPattern;
  LONG       TileSize;
  HOST_DATA  MaskPattern;

  pPattern = &MaskPattern.dwData;

  TileSize = ppdev->lTileSize;
  REQUIRE(3);
  LL_MBLTEXT (TileSize, (1024/TileSize));

  DWcnt = tileszx / sizeof(DWORD);

  // Copy the mask data into the 64x64 space with unused portion
  // fill with AND or XOR default mask value.
  cnt = DWcnt;
  k = 0;
  for (i=0; i < 64; i++)
  {
    // Copy XOR mask
    for (j=0; j < 8; j++)
    {
      // Copy one screen line mask data from source to destination
      if ((j < lSrcDelta) && (i < cy))
      {
         MaskPattern.bData[k++] = *pXORSrcScan;
         pXORSrcScan++;
      }
      else
      {
         MaskPattern.bData[k++] = 0x0;
      };
  
      if (k > 3)
      {
		 REQUIRE(1);
         LL32 (grHOSTDATA[0], *pPattern);

         k = 0;
         cnt--;
      };  // endif (k > 3)
    }; // endfor j

    // Copy AND mask
    for (j=0; j < 8; j++)
    {
      // Copy one screen line mask data from source to destination
      if ((j < lSrcDelta) && (i < cy))
      {
         MaskPattern.bData[k++] = *pANDSrcScan;
         pANDSrcScan++;
      }
      else
      {
         MaskPattern.bData[k++] = 0xFF;
      };
  
      if (k > 3)
      {
         *pPattern = ~ *pPattern;
		 REQUIRE(1);
         LL32 (grHOSTDATA[0], *pPattern);

         k = 0;
         cnt--;
      };  // endif (k > 3)
    }; // endfor j

    // Check whether one tile row size of host data is written to the
    // HOSTDATA register. 
    if (cnt == 0)
    {
       // Reset the row data count
       cnt = DWcnt;
    };  // endif (cnt == 0)
  }; // end for i
};
 


/****************************************************************************
* FUNCTION NAME: RestoreSaveShowCursor()
*
* DESCRIPTION:   Restore the screen image (if needed), save the new
*                cursor location the image to offscreen memory and
*                show the cursor in the new location
*
* REVISION HISTORY:
*   6/20/95     Benny Ng      Initial version
****************************************************************************/
VOID RestoreSaveShowCursor(PPDEV ppdev,
                           LONG  x,
                           LONG  y)
{
  ULONG  curloc;
  LONG   ltmpX, ltmpY;

  DISPDBG((CURSOR_DBG_LEVEL, "DrvMovePointer - RestoreSaveShowCursor\n"));

    ltmpX = x;
    ltmpY = y;

    // Set Hw cursor preset register
    curloc = 0;

    if ((ltmpY = (y - ppdev->PtrYHotSpot)) < 0)
    {
       curloc = (-ltmpY) & 0x7F;
       ltmpY = 0;
    }

    if ((ltmpX = (x - ppdev->PtrXHotSpot)) < 0)
    {
       curloc = curloc | (((-ltmpX) << 8) & 0x7F00);
       ltmpX = 0;
    }

    LL16 (grCursor_Preset, curloc);

    // Set Hw cursor X & Y registers
    LL16 (grCursor_X, (WORD)ltmpX);
    LL16 (grCursor_Y, (WORD)ltmpY);

    return;
}; 



/****************************************************************************
* FUNCTION NAME: ConvertMaskBufToLinearAddr()
*
* DESCRIPTION:   Convert the HW cursor mask buffer address to linear offset
*                address.
*
* Input:         Pointer to the OFMHDL structure.
*
* Output:        32-bits Linear address pointer.
*
* REVISION HISTORY:
*   6/12/95     Benny Ng      Initial version
****************************************************************************/
ULONG ConvertMaskBufToLinearAddr(PPDEV ppdev)
{
#if DRIVER_5465
  ULONG  Page;
  ULONG  Bank;
  ULONG  CurLoc;
  ULONG  DP;
#endif  // DRIVER_5465

  ULONG  retaddr;
  ULONG  xtile, ytile;
  ULONG  tileszx, tileszy;
  ULONG  tileno;
  ULONG  xByteOffset, yByteOffset;
  ULONG  bpp;
  ULONG  TilesPerLine, Interleave;

#ifdef DBGDISP
  DISPDBG((CURSOR_DBG_LEVEL, "ConvertMaskBufToLinearAddr\n"));
#endif

  // Calculate the linear address from the X & Y coordinate
  if ((ppdev->lTileSize == (LONG) 128) || (ppdev->lTileSize == (LONG) 256))
  {
    if (ppdev->lTileSize == (LONG) 128)
    {
        tileszx = 128;
        tileszy = 16;
    }
    else if (ppdev->lTileSize == (LONG) 256)
    {
        tileszx = 256;
        tileszy = 8;
    };

    Interleave = LLDR_SZ(grTILE_CTRL);
    TilesPerLine = Interleave & 0x3F;
    Interleave = ((Interleave >> 6) & 0x3);
    Interleave = 1 << Interleave;
     
    bpp = ppdev->ulBitCount/8;

    #if DRIVER_5465
         DP = TilesPerLine * tileszx;
         Page = (ppdev->PtrMaskHandle->aligned_y) /
                (tileszy * Interleave) * TilesPerLine +
                (ppdev->PtrMaskHandle->aligned_x/tileszx);

         Bank = (((ppdev->PtrMaskHandle->aligned_x / tileszx) +
                  (ppdev->PtrMaskHandle->aligned_y / tileszy)) % Interleave) +
                 ((Page/512) << (Interleave >> 1));

         Page = Page & 0x1FF;
       
         CurLoc = (Bank<<20) + (Page<<11) +
                  (ppdev->PtrMaskHandle->aligned_y % tileszy) * tileszx;
       
         retaddr = CurLoc;
    #else
         // calculate x tile coordinate and byte offset into tile due to x
         // xTileCoord  = x / TileWidth
         // xByteOffset = x % TileWidth

         xtile = ppdev->PtrMaskHandle->aligned_x / tileszx;
         xByteOffset = ppdev->PtrMaskHandle->aligned_x % tileszx;

         // calculate y tile coordinate and byte offset into tile due to y
         // yTileCoord  =  y / TileHeight
         // yByteOffset = (y % TileHeight) * TileWidth
         // byteOffset  = yByteOffset + xByteOffset

         ytile = ppdev->PtrMaskHandle->aligned_y / tileszy;
         yByteOffset = (ppdev->PtrMaskHandle->aligned_y % tileszy) * tileszx;

         // calculate tile number from start of RDRAM
         // (the LS 0,1,or 2 bits of this will become the bank selects based
         //	on interleave of 1,2,or 4)
         //
         //  tileNo = ((yTile / Interleave) * TilesPerLine) * Interleave
         //           + xTile * Interleave
         //	         + (yTile + xTile) % Interleave
         // (the "+xTile" takes care of interleave rotation)

         tileno = (((ytile / Interleave) * TilesPerLine) * Interleave)
                  + (xtile * Interleave)
                  + ((ytile + xtile) % Interleave);

         // calculate linear offset
         //   LinOffset = tileNo * BYTES_PER_TILE + xByteOffset + yByteOffset
         retaddr = (tileno * BYTES_PER_TILE) + xByteOffset + yByteOffset;
    #endif  // DRIVER_5465
  }
  else 
  {
     // Calculate the linear address from the X & Y coordinate
     retaddr = (ULONG) ppdev->PtrMaskHandle->aligned_x +
               (ULONG) ppdev->lDeltaScreen * ppdev->PtrMaskHandle->aligned_y;
  };

  return (retaddr);
};