/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT    Copyright (C) 1995 IBM Corporation                           */
/*                                                                           */
/*    The following IBM OS/2 WARP source code is provided to you solely for  */
/*    the purpose of assisting you in your development of OS/2 WARP device   */
/*    drivers. You may use this code in accordance with the IBM License      */
/*    Agreement provided in the IBM Device Driver Source Kit for OS/2. This  */
/*    Copyright statement may not be removed.                                */
/*                                                                           */
/*****************************************************************************/
/**********************************************************************/
/*                                                                    */
/*   Module          = EDDMCURS                                       */
/*                                                                    */
/*   Description     = Display Device Driver cursor functions         */
/*                                                                    */
/*   Function        = DeviceSetCursor sets the cursor shape          */
/*                                                                    */
/*   Reference       = Winthorn Functional Specification              */
/*                     Device Driver Interface Specification          */
/*                     Display Device Driver Design Specification     */
/*                                                                    */
/*                                                                    */
/**********************************************************************/
#define INCL_DOSPROCESS
#define INCL_DDIMISC
#include <eddinclt.h>

#include <eddhcone.h>
#include <eddhtype.h>
#include <edddtypt.h>
#include <eddbtypt.h>
#include <eddmcone.h>
#include <eddmextf.h>

#ifdef MATROX
#include <eddfext.h>
#endif /* MATROX */

#include <eddgextf.h>

#include <eddhmacr.h>

#include <hwaccess.h>
#include <cursor.h>
#include <plasma.h>
#include <cacheman.h>

extern DDTType          DDT;
extern CURSORDATA       cursor_data;

#ifndef _8514
extern MMReg            ShadowXGARegs;
#else
#include <8514.h>
extern MM8514Reg        Shadow8514Regs;
#endif
extern SHORT            softDrawInUse;
extern BitmapHeader     DirectListEntry;

extern ULONG            pPhunkPhys;
extern PBYTE            pPhunkVirt;

extern BOOL             SWCursorForced;

ULONG CopyMemoryToBTDac( PVOID );

/**********************************************************************/
/* DeviceSetCursor sets the cursor shape to the given value           */
/**********************************************************************/

DDIENTRY eddm_DeviceSetCursor (HDC            hdc,
                               PPOINTL        ArgHotSpot,
                               ULONG          ArgBitmap,
                               PDC            pdcArg,
                               ULONG          FunN)

{
#define TFUNC "eddm_DeviceSetCursor"
    /******************************************************************/
    /* Local variables                                                */
    /******************************************************************/
    ULONG               i;              /* loop variable              */
    BYTE                Mask;           /* to isolate bits in bitmap  */
    ULONG               ArrayCount;     /* array count for cursor_bits*/
    PBYTE               pANDPlane;      /* pointer to AND plane       */
    PBYTE               pXORPlane;      /* pointer to XOR plane       */
    ULONG               Work;           /* work variable              */
    PBYTE               pBitmap;        /* pointer to bitmap data     */
    ULONG               width;          /* cursor width               */
    ULONG               height;         /* cursor height              */
    ULONG               twiceheight;    /* twice cursor height        */
    ULONG               BMsuppliedwidth;/* hw width of given bitmap   */
    ULONG               BMsuppliedheight;/* hw height of given bitmap */
    ULONG               BMCursorHeight; /* required to stop compiler  */
    ULONG               BMCursorWidth;  /* reading from h/w registers */
    ULONG               BaseAddress;    /*    ditto                   */
    LONG                place;          /* used determining widtheigth*/
    ULONG               masksize;       /* mask size in bytes         */
    SHORT               tempSoftDrawInUse;

    EnterDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);

    /******************************************************************/
    /* Check for a null bitmap handle being passed in.                */
    /* or a null bitmap identified by the handle                      */
    /******************************************************************/
    if ( !ArgBitmap ||
         !(pBitmap = ((pBitmapHeader)ArgBitmap)->Bitmap))
    {
        /**************************************************************/
        /* The bitmap is null, which means that we should             */
        /* turn off the cursor.                                       */
        /**************************************************************/
        cursor_data.cursor_status &= ~CURSOR_VISIBLE;

        if (cursor_data.cursor_status & CURSOR_SOFTWARE)
        {
            /**********************************************************/
            /* The cursor is draw in software, so we must actually    */
            /* remove it.                                             */
            /**********************************************************/
            remove_software_cursor();
        }

#if defined S3 | XGA
        else
        {
            /**********************************************************/
            /* The h/w cursor is removed by setting the invisible     */
            /* flag.                                                  */
            /**********************************************************/
            cursor_data.draw_sprite_flags = SPRITE_INVISIBLE;
            SetSpriteShape();
        }
#endif
        ExitDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);
        return(OK);
    }

    /******************************************************************/
    /* Check the cursor bitmap dimensions.                            */
    /* The bitmap should be in (1,1) format                           */
    /* (we dont check the format - we assume its ok)                  */
    /*  width and height depend on the cursorsizes table              */
    /******************************************************************/
    width       = ((pBitmapHeader)ArgBitmap)->Info.Width;
    twiceheight = ((pBitmapHeader)ArgBitmap)->Info.Height;
    height      = twiceheight/2;

    /******************************************************************/
    /* Check that the cursor definition passed in is not larger than  */
    /* the maximum size we can handle for the current screen size.    */
    /******************************************************************/
    if ((width  > DDT.CursorWidth) ||
        (height > DDT.CursorHeight))
    {
        LOGERR(TFUNC, "Invalid cursor size", ArgHotSpot, 2,
                                               PMERR_INV_CURSOR_BITMAP);
        goto SETCURSOR_ERR_EXIT;
    }

    /******************************************************************/
    /* if we get here we have a cursor to display                     */
    /******************************************************************/
    cursor_data.cursor_status |= CURSOR_VISIBLE;

    /******************************************************************/
    /* Set up pointers to the AND and XOR masks and set array count   */
    /******************************************************************/
    pANDPlane = (PBYTE)pBitmap;
    pXORPlane = (PBYTE)(pBitmap + width * height / 8 );
    ArrayCount = 0;

    /******************************************************************/
    /* before we change the cursor data, wait until MoveCursor is     */
    /* not executing.                                                 */
    /******************************************************************/
    eddm_Interrupts_Off();
    while (cursor_data.cursor_status & CURSOR_BUSY)
    {
         eddm_Interrupts_On();
         DosSleep(0L);
         eddm_Interrupts_Off();
    }

    /******************************************************************/
    /* further MoveCursor drawing can be disabled by setting the      */
    /* cursor status to invisible. This allows us to reenable         */
    /* interrupts and change the cursor data knowing that we will     */
    /* not conflict with MoveCursor                                   */
    /******************************************************************/
    cursor_data.cursor_status &= ~CURSOR_VISIBLE;
    eddm_Interrupts_On();

    /******************************************************************/
    /* Set up the global fields with the values of the new cursor     */
    /* these values are independant of whether we use a software or   */
    /* a hardware cursor                                              */
    /******************************************************************/
    cursor_data.cursor_width  = width;
    cursor_data.cursor_height = height;
    cursor_data.hotspot_x     = ArgHotSpot->x;
    cursor_data.hotspot_y     = ArgHotSpot->y;

    /******************************************************************/
    /* Plasma uses a software cursor                                  */
    /******************************************************************/
    if ((plasma_status & PLASMA_ENABLED) ||
        SWCursorForced )
    {
        cursor_data.cursor_status |= CURSOR_SOFTWARE;

        /**************************************************************/
        /* Remove the old cursor (Restore the old screen contents)    */
        /**************************************************************/
        remove_software_cursor();

        /**************************************************************/
        /* we must set up the data for the software cursor            */
        /**************************************************************/

        /**************************************************************/
        /* find the 'used' size of the cursor - ie the part which is  */
        /* actually affected by the AND and XOR masks                 */
        /* the unused part is where the AND mask is 1 but the XOR     */
        /* mask is 0                                                  */
        /* (for simplicity we only consider full bytes)               */
        /**************************************************************/
        /**************************************************************/
        /* first consider the height                                  */
        /**************************************************************/
        masksize = width * height / 8;
        i = masksize - 1;
        while (i && pBitmap[i         ] == 0xff &&
                    pBitmap[i+masksize] == 0x00)
        {
            i--;
        }
        cursor_data.software_cursor.used.y = i / (width / 8) + 1;

        /**************************************************************/
        /* then consider the width                                    */
        /**************************************************************/
        place =
        i     = masksize - 1;
        while (i && pBitmap[place         ] == 0xff &&
                    pBitmap[place+masksize] == 0x00)
        {
            /**********************************************************/
            /* move one byte up the column                            */
            /**********************************************************/
            place -= (height / 8);
            if (place < 0)
            {
                /******************************************************/
                /* we've got to the top of one vertical column        */
                /* so move to the bottom of the previous column       */
                /******************************************************/
                place += (masksize - 1);
            }
            i--;
        }
        cursor_data.software_cursor.used.x = (i / height + 1) * 8;

        /**************************************************************/
        /* adjust the hotspot to take account of only using part      */
        /* of the cursor rectangle                                    */
        /* (hotspot is relative to the bottom left of the used part)  */
        /**************************************************************/
        cursor_data.hotspot_y -= (height - cursor_data.software_cursor.used.y);

        /**************************************************************/
        /* set the hardware versions of the used sizes                */
        /**************************************************************/
        cursor_data.software_cursor.hwusedsize.x =
                                   cursor_data.software_cursor.used.x - 1;
        cursor_data.software_cursor.hwusedsize.y =
                                   cursor_data.software_cursor.used.y - 1;

        /**************************************************************/
        /* put these calculated values into local variables so that   */
        /* when they are written to more than one h/w register the    */
        /* compiler reads the value from the local variable, and      */
        /* does not try and read the value back from the hardware     */
        /**************************************************************/
        BMCursorWidth    = DDT.CursorWidth  - 1;
        BMCursorHeight   = DDT.CursorHeight * 2 - 1;
        BMsuppliedwidth  = width - 1;
        BMsuppliedheight = twiceheight - 1;

        /**************************************************************/
        /* Copy the masks into VRAM                                   */
        /* This copy has to be done via the PHUNK directly (rather    */
        /* than indirectly using CopyMaskToVRAM) because              */
        /* CopyMaskToVram does not have the capabilities of           */
        /* specifying different size source and destination pixmaps   */
        /* that we require.                                           */
        /**************************************************************/

#ifdef _8514

        /**************************************************************/
        /* Copy the bitmap and masks directly to VRAM if 8514.        */
        /**************************************************************/

        /* Copy the AND mask to offscreen VRAM */
        cursor_data.software_cursor.andmask++;
        cursor_data.software_cursor.andmask &= 0xfffffffe;
        CopyMaskToVRAM((PVOID)pANDPlane, cursor_data.software_cursor.andmask, width - 1, height - 1, ONE_BPP);

        /* Copy the XOR mask to offscreen VRAM */
        cursor_data.software_cursor.xormask++;
        cursor_data.software_cursor.xormask &= 0xfffffffe;
        CopyMaskToVRAM((PVOID)pXORPlane, cursor_data.software_cursor.xormask, width - 1, height - 1, ONE_BPP);

        cursor_data.cursor_status &= ~CURSOR_COLOUR;
#else

        /**************************************************************/
        /* Copy the masks to the PHUNK (which is locked always).      */
        /* There should always be enough space !                      */
        /**************************************************************/

        memcpy( pPhunkVirt,
                (PVOID)pBitmap,
                (width * twiceheight / 8));

        /**************************************************************/
        /* NEW WAY STARTS HERE                                        */
        /* set up a colour cursor corresponding to the mono definition*/
        /**************************************************************/

        /**************************************************************/
        /* note !!!!!! marks values set to width variables when you   */
        /*       might have expected to use height variables          */
        /* (because we know the supplied height is double the height  */
        /* of each mask, and also double the width!).                 */
        /**************************************************************/

        /**************************************************************/
        /* copy the AND mask                                          */
        /**************************************************************/

        /**************************************************************/
        /* select the destination pixel map and set it up             */
        /**************************************************************/
        ShadowXGARegs.PixMapFormatA = ONE_BPP | INTEL;
        ShadowXGARegs.PixMapBaseA   = cursor_data.software_cursor.andmask;
        ShadowXGARegs.PixMapWidthA  = BMCursorWidth;
        ShadowXGARegs.PixMapHeightA = BMCursorHeight;

        /**************************************************************/
        /* set up the source in the hardware (AND mask)               */
        /**************************************************************/
#ifdef MATROX
        if (RunningOnMatrox())
        {
            BaseAddress = (ULONG)pPhunkVirt;
        }
        else
        {
#endif /* MATROX */
            BaseAddress = pPhunkPhys;
#ifdef MATROX
        }
#endif /* MATROX */
        ShadowXGARegs.PixMapFormatB = ONE_BPP | MOTOROLA;
        ShadowXGARegs.PixMapBaseB   = BaseAddress;
        ShadowXGARegs.PixMapWidthB  = BMsuppliedwidth;
        ShadowXGARegs.PixMapHeightB = BMsuppliedheight;

        /**************************************************************/
        /* Now the blt coordinates and dimensions                     */
        /**************************************************************/
        ShadowXGARegs.SrcXAddr =
        ShadowXGARegs.SrcYAddr =
        ShadowXGARegs.DstXAddr =
        ShadowXGARegs.DstYAddr = 0;

        ShadowXGARegs.OpDim1   = BMsuppliedwidth;
        ShadowXGARegs.OpDim2   = BMsuppliedwidth;     /* !!!!!!! */

        /**************************************************************/
        /* select a copy mix                                          */
        /**************************************************************/
        ShadowXGARegs.FgMix =
        ShadowXGARegs.BgMix = HWMIX_SOURCE;
        ShadowXGARegs.ColCompCond = COLCOMP_ALWAYS;

        /**************************************************************/
        /* set up the pixel op value to do the blt                    */
        /**************************************************************/
        ShadowXGARegs.PixOp = BACK_SRC_SRC_PIX_MAP |
                              FORE_SRC_SRC_PIX_MAP |
                              STEP_PXBLT |
                              SRC_PIX_MAP_B |
                              DST_PIX_MAP_A |
                              PAT_PIX_MAP_FORE |
                              MASK_PIX_MAP_OFF |
                              DRAW_MODE_DONTCARE |
                              DIR_OCTANT_LRTB;

        /**************************************************************/
        /* Set softDrawInUse to false - we must use the real XGA HW   */
        /* to draw the sprite. Keep a copy of the old softDrawInUse   */
        /* because we have not changed the other variables which      */
        /* are normally changed when switching between SW and HW      */
        /* drawing modes - so we must restore it before we return.    */
        /**************************************************************/
        tempSoftDrawInUse = softDrawInUse;
        softDrawInUse = FALSE;

        /**************************************************************/
        /* And go for it...                                           */
        /**************************************************************/
        TransferShadowRegisters( TSR_MAP_A |
                                 TSR_MAP_B |
                                 TSR_COLOUR_MIX |
                                 TSR_COORDINATES |
                                 TSR_PIXELOP );

        /**************************************************************/
        /* copy the XOR mask                                          */
        /**************************************************************/

        /**************************************************************/
        /* select the destination pixel map and set it up             */
        /**************************************************************/
        ShadowXGARegs.PixMapFormatA = ONE_BPP | INTEL;
        ShadowXGARegs.PixMapBaseA   = cursor_data.software_cursor.xormask;
        ShadowXGARegs.PixMapWidthA  = BMCursorWidth;
        ShadowXGARegs.PixMapHeightA = BMCursorWidth;  /* !!!!!!! */

        /**************************************************************/
        /* set up the source in the hardware (XOR mask)               */
        /**************************************************************/
        BaseAddress += (width * height / 8);
        ShadowXGARegs.PixMapFormatB = ONE_BPP | MOTOROLA;
        ShadowXGARegs.PixMapBaseB   = BaseAddress;
        ShadowXGARegs.PixMapWidthB  = BMsuppliedwidth;
        ShadowXGARegs.PixMapHeightB = BMsuppliedwidth;   /* !!!!!! */

        /**************************************************************/
        /* Now the blt coordinates and dimensions                     */
        /**************************************************************/
        ShadowXGARegs.SrcXAddr =
        ShadowXGARegs.SrcYAddr =
        ShadowXGARegs.DstXAddr =
        ShadowXGARegs.DstYAddr = 0;

        ShadowXGARegs.OpDim1   = BMsuppliedwidth;
        ShadowXGARegs.OpDim2   = BMsuppliedwidth;     /* !!!!!!! */

        /**************************************************************/
        /* select a copy mix                                          */
        /**************************************************************/
        ShadowXGARegs.FgMix =
        ShadowXGARegs.BgMix = HWMIX_SOURCE;

        /**************************************************************/
        /* set up the pixel op to do the blt                          */
        /**************************************************************/
        ShadowXGARegs.PixOp = BACK_SRC_SRC_PIX_MAP |
                              FORE_SRC_SRC_PIX_MAP |
                              STEP_PXBLT |
                              SRC_PIX_MAP_B |
                              DST_PIX_MAP_A |
                              PAT_PIX_MAP_FORE |
                              MASK_PIX_MAP_OFF |
                              DRAW_MODE_DONTCARE |
                              DIR_OCTANT_LRTB;

        /**************************************************************/
        /* And go for it..                                            */
        /**************************************************************/
        TransferShadowRegisters( TSR_MAP_A |
                                 TSR_MAP_B |
                                 TSR_COLOUR_MIX |
                                 TSR_COORDINATES |
                                 TSR_PIXELOP );

        /**************************************************************/
        /* now expand the XOR mask to a screen format colour cursor   */
        /**************************************************************/

        /**************************************************************/
        /* select the destination pixel map and set it up             */
        /*                                                            */
        /* this colour data is the same width and height              */
        /**************************************************************/
        ShadowXGARegs.PixMapFormatA =
                             DirectListEntry.Info.HWFormat & ~MOTOROLA;
        ShadowXGARegs.PixMapBaseA   = cursor_data.software_cursor.bm;
        ShadowXGARegs.PixMapWidthA  = BMCursorWidth;
        ShadowXGARegs.PixMapHeightA = BMCursorWidth;    /* !!!!!! */

        /**************************************************************/
        /* set up the source in the hardware (XOR mask again)         */
        /* this variation uses the XOR mask we just copied to VRAM    */
        /**************************************************************/
        BaseAddress = cursor_data.software_cursor.xormask;
        ShadowXGARegs.PixMapFormatB = ONE_BPP | MOTOROLA;
        ShadowXGARegs.PixMapBaseB   = BaseAddress;
        ShadowXGARegs.PixMapWidthB  = BMCursorWidth;
        ShadowXGARegs.PixMapHeightB = BMCursorWidth;   /* !!!!!!!! */

        /**************************************************************/
        /* Now the blt coordinates and dimensions                     */
        /**************************************************************/
        ShadowXGARegs.PatXAddr =
        ShadowXGARegs.PatYAddr =
        ShadowXGARegs.DstXAddr =
        ShadowXGARegs.DstYAddr = 0;

        ShadowXGARegs.OpDim1   = BMsuppliedwidth;
        ShadowXGARegs.OpDim2   = BMsuppliedwidth;       /* !!!!!!! */

        /**************************************************************/
        /* Select expansion copy                                      */
        /* We want the colors to go to black and white.               */
        /**************************************************************/
        ShadowXGARegs.FgMix =
        ShadowXGARegs.BgMix = HWMIX_SOURCE;
        ShadowXGARegs.ColCompCond = COLCOMP_ALWAYS;
        ShadowXGARegs.FgCol = 0xFFFF;
        ShadowXGARegs.BgCol = 0x0000;

        /**************************************************************/
        /* Set up the pixel op the do the blt                         */
        /**************************************************************/
        ShadowXGARegs.PixOp = BACK_SRC_BACK_COL |
                              FORE_SRC_FORE_COL |
                              STEP_PXBLT |
                              SRC_PIX_MAP_DONTCARE |
                              DST_PIX_MAP_A |
                              PAT_PIX_MAP_B |
                              MASK_PIX_MAP_OFF |
                              DRAW_MODE_DONTCARE |
                              DIR_OCTANT_LRTB;

        /**************************************************************/
        /* And go for it..                                            */
        /**************************************************************/
        TransferShadowRegisters( TSR_MAP_A |
                                 TSR_MAP_B |
                                 TSR_COLOUR_MIX |
                                 TSR_COORDINATES |
                                 TSR_PIXELOP );

        /**************************************************************/
        /* Restore the drawing mode variable (to keep consistent with */
        /* other drawing mode vars).                                  */
        /**************************************************************/
        softDrawInUse = tempSoftDrawInUse;

#endif /* ~_8514 */
    }

#if defined XGA  || defined S3

    else
    {


#ifdef XGA
        /**************************************************************/
        /* Convert the supplied bitmap to the format required by the  */
        /* HW.  HW format is a (2,1) bitmap with the first bit from   */
        /* the AND mask and the second from the XOR.                  */
        /**************************************************************/

        /**************************************************************/
        /* need to change this yet to cope with non dword aligned rows*/
        /* Raj                                                        */
        /**************************************************************/

        for (Work = 0, Mask = 0x80, i = height * width; i--; )
        {
            /**********************************************************/
            /* Shift the next bit from XOR plane into work variable   */
            /**********************************************************/
            if (*pXORPlane & Mask)
            {
                Work |= 0x4000;
            }

            /**********************************************************/
            /* Shift the next bit from AND plane into work variable   */
            /**********************************************************/
            if (*pANDPlane & Mask)
            {
                Work |= 0x8000;
            }

            /**********************************************************/
            /* Check if we have a complete word to write into array   */
            /**********************************************************/
            if ( Mask & 0x01 )
            {
                /******************************************************/
                /* Store the word in the HW cursor definition and     */
                /* advance the mask pointers                          */
                /******************************************************/
                cursor_data.cursor_bits[ArrayCount++] = (BYTE)Work;
                cursor_data.cursor_bits[ArrayCount++] = (BYTE)(Work / 256);
                pANDPlane++;
                pXORPlane++;

                /******************************************************/
                /* reset the mask to the most significant bit and     */
                /* clear out the work variable                        */
                /******************************************************/
                Mask = 0x80;
                Work = 0;

            }

            else /* not yet got a complete word to write */
            {
                /******************************************************/
                /* Shift the work word right two so the two most      */
                /* significant bits are free for the next AND and XOR */
                /* bits. Shift the mask by one to access the next bit */
                /* right in the masks                                 */
                /******************************************************/
                Work >>= 2;
                Mask >>= 1;
            }

        } /* for each bit in the mask */
#endif
#ifdef S3
       /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
       /* S3 Hardware Cursor buffer set up.                                       */
       /*                                                                         */
       /* is defined as follows:                                                  */
       /* 2 Bytes of AND mask across 8 planes followed by 2 Bytes of XOR mask     */
       /* across 8 planes repetitivly until finished with AND/XOR mask data.     */
       /*                                                                         */
       /*  PLANE                                                                  */
       /*    7   A   A   X   X   A   A   X   X                                    */
       /*    6   A   A   X   X   A   A   X   X                                    */
       /*    5   A   A   X   X   A   A   X   X                                    */
       /*    4   A   A   X   X   A   A   X   X                                    */
       /*    3   A   A   X   X   A   A   X   X                                    */
       /*    2   A   A   X   X   A   A   X   X                                    */
       /*    1   A   A   X   X   A   A   X   X                                    */
       /*    0   A   A   X   X   A   A   X   X                                    */
       /*   BIT  0   1   2   3   4   5   6   7   .   .   .                        */
       /*                                                                         */
       /* where A = AND MASK and X = XOR MASK                                     */
       /* Our buffer will need to be padded if the user supplied bitmap is        */
       /* smaller than the hardware bitmap.                                       */
       /*                                                                         */
       /* Cursor Colors:                                                          */
       /*                Foreground                  Background                   */
       /*    8Bit - Cursor Location High          Cursor Location Low             */
       /*   16Bit - HW Graph Cur FG Stack        HW Graph Cur BG Stack            */
       /*   24Bit -           "                            "                      */
       /*                                                                         */
       /* Cursor Mode:                                                            */
       /*   Register 3D4 Index 45                                                 */
       /*      Bit 0 - enable/disable hw cursor                                   */
       /*      Bit 2 - set up hw cursor for 16Bit color mode                      */
       /*      Bit 3 - set up hw cursor for 24Bit color mode                      */
       /*                                                                         */
       /* NOTE: For 16 and 24 Bit color the hw cursor definition remains the same */
       /*       The only difference is how the CopyMemoryToVram function handles  */
       /*       the mask data. In the 16Bpp case the function swaps the bytes     */
       /*       when writing to the HW, so we will adjust for this when creating  */
       /*       the mask data.                                                    */
       /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
       {

           ULONG     j;                               // counter
           PBYTE     ptmp = cursor_data.cursor_bits;
           ULONG     ulScanL;
           ULONG     ulBitCount;

           // defect 75487 we need to turn the cursor off while loading it
           // the xga does not load it until it is output we do it much earlier.
           // so move it off screen
           cursor_data.draw_sprite_x =(USHORT)(cursor_data.software_cursor.andmask >> 16);
           cursor_data.draw_sprite_y =(USHORT)(cursor_data.software_cursor.andmask);
           if((DDT.fScreenFlags & USE_BROOKDAC) && (HWResolution > 3 ))
           {
              // we need to really turn off the brooktree cursor to eliminate
              // sparkle - we dont want to do this stuff for s3 cursor
              // because it causes a timing problem with multiple set cursor
              // calls (x 100's).
              cursor_data.adapter_id = S3_WITH_BROOK_DAC;
              // we dont do these for s3 hwcursor
              cursor_data.draw_sprite_flags = SPRITE_INVISIBLE;
              SetSpriteShape();
           }

           /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
           /* Fill the entire buffer transparent.                       */
           /* pattern 2 bytes of AND all 1's and 2 bytes of XOR all 0's */
           /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
           memset(cursor_data.cursor_bits, 0xFF, 1024);

           for(i=2;i<1024;i+=4)
           {
              ptmp[i] = 0x00;
              ptmp[i+1] = 0x00;
           }

           /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
           /* Now set the cursor masks into the hardware format.        */
           /* We have to take into account odd bytes and copy them at   */
           /* the end of each scan.                                     */
           /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
           if((DDT.fScreenFlags & USE_BROOKDAC) && (HWResolution > 3 ))
           {
              for(i=0;i < height;i++)
              {
                 ptmp = (PBYTE)(cursor_data.cursor_bits + (i * 16));
                 for(j=0;j < (width / 8) - 1;j+=2, pANDPlane += 2, pXORPlane += 2)
                 {
                    ptmp[0] = pANDPlane[0];
                    ptmp[1] = pANDPlane[1];
                    ptmp[2] = pXORPlane[0];
                    ptmp[3] = pXORPlane[1];
                    ptmp += 4;
                 }

                 if (j * 8 < width)
                 {
                    ptmp[0] = pANDPlane[0];
                    ptmp[2] = pXORPlane[0];
                    pANDPlane++;
                    pXORPlane++;
                 }
              }

           }
           else
           {
              for(i=0;i < height;i++)
              {
                 ptmp = (PBYTE)(cursor_data.cursor_bits + (i * 16));
                 for(j=0;j < (width / 8) - 1;j+=2, pANDPlane += 2, pXORPlane += 2)
                 {
                    if(cursor_data.screen_hw_format == SIXTEEN_BITS_PER_PEL)
                    {
                       ptmp[0] = pANDPlane[1];
                       ptmp[1] = pANDPlane[0];
                       ptmp[2] = pXORPlane[1];
                       ptmp[3] = pXORPlane[0];
                    } else {
                       ptmp[0] = pANDPlane[0];
                       ptmp[1] = pANDPlane[1];
                       ptmp[2] = pXORPlane[0];
                       ptmp[3] = pXORPlane[1];
                    }
                    ptmp += 4;
                 }

                 if (j * 8 < width)
                 {
                    if(cursor_data.screen_hw_format == SIXTEEN_BITS_PER_PEL)
                    {
                       ptmp[1] = pANDPlane[0];
                       ptmp[3] = pXORPlane[0];
                    } else {
                       ptmp[0] = pANDPlane[0];
                       ptmp[2] = pXORPlane[0];
                    }
                    pANDPlane++;
                    pXORPlane++;
                 }
              }

           }

           if(cursor_data.screen_hw_format == SIXTEEN_BITS_PER_PEL)
           {
              ulScanL = 511;
              ulBitCount = SIXTEEN_BPP;
           } else {
              ulScanL = 1023;
              ulBitCount = EIGHT_BPP;
           }

            /* We must hide the cursor before reseting it. Otherwise */
            /* the redrawing will cause the cursor to dance.. 85279 */
            cursor_data.draw_sprite_flags = SPRITE_INVISIBLE; 
            SetSpriteShape();                                 

           /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
           /* Now fill offscreen vram with the new cursor image.        */
           /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
           if((DDT.fScreenFlags & USE_BROOKDAC) && (HWResolution > 3 ))
           {
              CopyMemoryToBTDac((PVOID)cursor_data.cursor_bits );
              //we dont do these for s3 hwcursor
              cursor_data.draw_sprite_x = cursor_data.new_cursor_x;
              cursor_data.draw_sprite_y = cursor_data.new_cursor_y;
           }
           else
           {
              CopyMemoryToVRAM((PVOID)cursor_data.cursor_bits,
                               (PVOID)cursor_data.cursor_hwvram,
                               ulScanL,
                               0L,
                               ulBitCount);

              cursor_data.adapter_id = S3_WITH_ATT_DAC;
           }

           /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
           /* If we had a colour cursor, its now time to turn it off.   */
           /* It will be faster just to set the flag every time instead */
           /* of checking and then setting it.                          */
           /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
           cursor_data.cursor_status &= ~CURSOR_COLOUR;
           //cursor_data.draw_sprite_x = cursor_data.new_cursor_x;
           //cursor_data.draw_sprite_y = cursor_data.new_cursor_y;
        }
#endif

#if defined XGA || defined S3
        /**************************************************************/
        /* if we are switching from a software cursor then remove it  */
        /* and disable the software cursor                            */
        /**************************************************************/
        if ( cursor_data.cursor_status & CURSOR_SOFTWARE )
        {
            /**********************************************************/
            /* make the cursor status invisible to prevent MoveCursor */
            /* doing any more drawing. It doesn't matter if it has    */
            /* already begun to draw since remove_software_cursor will*/
            /* wait for it to finish. This allows us to reset the     */
            /* colour cursor flag and be sure that MoveCursor won't   */
            /* draw a monochrome cursor over the colour cursor we are */
            /* removing                                               */
            /**********************************************************/
            cursor_data.cursor_status &= ~CURSOR_VISIBLE & ~CURSOR_SOFTWARE;
            remove_software_cursor();

            /**********************************************************/
            /* make the cursor status visible to allow MoveCursor to  */
            /* do drawing                                             */
            /**********************************************************/
            cursor_data.cursor_status |= CURSOR_VISIBLE;

        }

        /**************************************************************/
        /* Set up draw_sprite parameter block                         */
        /**************************************************************/
        cursor_data.draw_sprite_hot_x = cursor_data.hotspot_x;

        /**************************************************************/
        /* Note the bodge here to cope with hotspots which lie outside*/
        /* the cursor definition. If this happens then we have to     */
        /* avoid giving a negative value in hssprite_data.hot_y to the*/
        /* hardware. The way this is done is to make the hotspot 0    */
        /* and then make the necessary adjustment in movecursor at    */
        /* the time the cursor is drawn.                              */
        /**************************************************************/
        if (cursor_data.hotspot_y >= height)
        {
            cursor_data.cursor_adjust = cursor_data.hotspot_y - height + 1;
            cursor_data.draw_sprite_hot_y = height - 1 -
                    cursor_data.hotspot_y + cursor_data.cursor_adjust;
            #pragma message(__FILE__"(814) : Fix this, always 0 --edb")
        }
        else
        {
            cursor_data.draw_sprite_hot_y = height - 1 -
                                                 cursor_data.hotspot_y;
            cursor_data.cursor_adjust = 0;
        }

        cursor_data.draw_sprite_width  = width;
        cursor_data.draw_sprite_height = height;

        /**************************************************************/
        /* Pass monochrome cursor definition to the HW                */
        /**************************************************************/
        cursor_data.draw_sprite_flags = SPRITE_VISIBLE; 
        SetSpriteShape(); 

    }

#endif
#endif  // S3 or XGA

    /******************************************************************/
    /* set the cursor redraw flag so the interrupt thread will redraw */
    /* using the latest position. This is mainly for colour cursors   */
    /* since HSPRITE will not have been called while the colour       */
    /* cursor was active. This means that the HSSPRITE call above     */
    /* will have redrawn the cursor at the last mono (ie. last        */
    /* HSPRITE) position. If we are not switching from a colour       */
    /* cursor here it doesn't do any harm to set this flag            */
    /* We can also set the status to visible again to allow           */
    /* MoveCursor to resume drawing                                   */
    /******************************************************************/
    cursor_data.cursor_status |= (CURSOR_REDRAW | CURSOR_VISIBLE);

    ExitDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);
    return(OK);

SETCURSOR_ERR_EXIT:
    ExitDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);
    return(ERROR_ZERO);
}

#ifdef S3
/**********************************************************************/
/* CopyMemoryToBTDac sets the cursor shape to the given value on the  */
/* BrookTree Dac or other similar DACS.                               */
/**********************************************************************/
ULONG CopyMemoryToBTDac( PVOID pBits )
{
   register USHORT  ax;
   register PBYTE   pTmp = pBits;

   // command reg 0
   outp(S3_NDX_PORT,0x55);
   ax = (USHORT)inp(S3_RW_PORT);
   ax &= 0xFC;
   ax |= 0x01;
   outp(S3_RW_PORT, ax);

   // select command reg 0 and set cr07 to 1
   // this allows access to command reg 3
   ax = (USHORT)inp(0x03C6);
   ax |= 0x10;
   outp(0x03C6,ax);

   // addr reg
   outp(S3_NDX_PORT,0x55);
   ax = (USHORT)inp(S3_RW_PORT);
   ax &= 0xFC;
   ax |= 0x00;
   outp(S3_RW_PORT, ax);

   // select addr reg
   outp(0x3C8,1);

   // command reg 3
   outp(S3_NDX_PORT,0x55);
   ax = (USHORT)inp(S3_RW_PORT);
   ax &= 0xFC;
   ax |= 0x02;
   outp(S3_RW_PORT, ax);

   // set cr32 for 64x64x2 cursor
   ax = (USHORT)inp(0x03C6);
   ax &= 0xF8;
   ax |= 0x04;
   outp(0x03C6,ax);

   // addr reg
   outp(S3_NDX_PORT,0x55);
   ax = (USHORT)inp(S3_RW_PORT);
   ax &= 0xFC;
   ax |= 0x00;
   outp(S3_RW_PORT, ax);

   // select addr reg
   outp(0x3C8,0);

   // addr reg
   outp(S3_NDX_PORT,0x55);
   ax = (USHORT)inp(S3_RW_PORT);
   ax &= 0xFC;
   ax |= 0x02;
   outp(S3_RW_PORT, ax);

   // now send data to the dac via 3C7h
   for ( ax=0;ax<256;ax++) {
      pTmp += 2;
      outp(0x03C7,*pTmp++);
      outp(0x03C7,*pTmp++);
   }

   pTmp = pBits;
   for ( ax=0;ax<256;ax++) {
      outp(0x03C7,*pTmp++);
      outp(0x03C7,*pTmp++);
      pTmp += 2;
   }

   // reset addr reg  @EKF
   outp(S3_NDX_PORT,0x55);
   ax = (USHORT)inp(S3_RW_PORT);
   ax &= 0xFC;
   outp(S3_RW_PORT, ax);

   return( 1L );

}
#endif S3

#undef TFUNC
