/*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          = EDDMCCRS                                       */
/*                                                                    */
/*   Description     = Display Device Driver cursor functions         */
/*                                                                    */
/*   Function        = SetColorCursoris sets the cursor shape for a   */
/*                     coloured cursor                                */
/*                                                                    */
/*   Reference       = Winthorn Functional Specification              */
/*                     Device Driver Interface Specification          */
/*                     Display Device Driver Design Specification     */
/*                                                                    */
/*                                                                    */
/**********************************************************************/
#ifdef DBCS                                                 
/**********************************************************************/
/* Change History:                                                    */
/*                                                                    */
/* Stamp Date   Origin         Description                            */
/* ---- ------ ------------ --------------------------------------    */
/* @D01 930601 Y.Nakamura   Fixed problem on color cursor             */
/*                           SetColorCursor (==> Drawn)               */
/*                           DeviceSetCursor (==> Erased)             */
/*                           SetColorCursor (==> Should be re-drawn,  */
/*                             but not as VISIBLE bit is OFF)         */
/*                                                                    */
/**********************************************************************/
#endif                                                      
#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 <eddbextf.h>
#include <eddmextf.h>
#include <eddgextf.h>

#include <eddhmacr.h>

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

extern DDTType          DDT;
extern BitmapHeader     DirectListEntry;
extern CURSORDATA       cursor_data;
extern SHORT            softDrawInUse;

#ifdef SEAMLESS
extern ULONG            fSeamlessActive;
extern PPFNL            EnginesDispatchTable;
#endif /* SEAMLESS */

#ifdef _8514
extern MM8514Reg           Shadow8514Regs;
#endif

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

DDIENTRY eddm_SetColorCursor (HDC            hdc,
                              PPOINTERINFO   ArgCursorInfo,
                              PDC            pdcArg,
                              ULONG          FunN)

{
    /******************************************************************/
    /* Local variables                                                */
    /******************************************************************/
    pBitmapHeader       MaskHeader;     /* AND/XOR bitmap header      */
    pBitmapHeader       ColourHeader;   /* colour bitmap header       */
    ULONG               BMCursorHeight; /* required to stop compiler  */
    ULONG               BMCursorWidth;  /* reading from h/w registers */

    EnterDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);

    /******************************************************************/
    /* Get access to the bitmap for the pointer (AND/XOR) definition  */
    /******************************************************************/
    MaskHeader = (pBitmapHeader)
                        GetDriverInfo32(ArgCursorInfo->hbmPointer,
                                        DI_HBITMAP,
                                        hdc);
    if (MaskHeader == (pBitmapHeader)(-1))
    {
        LOGERR(TFUNC, "No Pointer bitmap", FNULL, 0, PMERR_INV_HBITMAP);
        goto SETCURSOR_ERR_EXIT;
    }

    /******************************************************************/
    /* Get access to the bitmap for the colour information            */
    /******************************************************************/
    ColourHeader = (pBitmapHeader)
                          GetDriverInfo32(ArgCursorInfo->hbmColor,
                                          DI_HBITMAP,
                                          hdc);
    if (ColourHeader == (pBitmapHeader)(-1))
    {
        LOGERR(TFUNC, "No Colour bitmap", FNULL, 0, PMERR_INV_HBITMAP);
        goto SETCURSOR_ERR_EXIT;
    }

    /******************************************************************/
    /* Validate the hot spot coordinate - check removed because it is */
    /* valid for the hotspot to lie outside the cursor shape          */
    /******************************************************************/
//Raj
//  if ((ArgCursorInfo->xHotspot < 0) ||
//      (ArgCursorInfo->xHotspot > MaskHeader->Info.Width) ||
//      (ArgCursorInfo->yHotspot < 0) ||
//      (ArgCursorInfo->xHotspot > (MaskHeader->Info.Height/2)))
//
//  {
//      LOGERR(TFUNC, "Invalid hotspot", ArgHotSpot, 2,
//                                                PMERR_INV_COORDINATE);
//      goto SETCURSOR_ERR_EXIT;
//  }
//Raj

    /******************************************************************/
    /* Check the dimensions of the two bitmaps - they should have the */
    /* same width and height.                                         */
    /* Also we check that they are within the size we can cope with.  */
    /******************************************************************/
    if ((MaskHeader->Info.Width    != ColourHeader->Info.Width)        ||
        (MaskHeader->Info.Width    >  DDT.CursorWidth)                 ||
        (MaskHeader->Info.Height   != (ColourHeader->Info.Height * 2)) ||
        (ColourHeader->Info.Height >  DDT.CursorHeight))
    {
        LOGERR(TFUNC, "Invalid cursor size", 0, 0,
                                               PMERR_INV_CURSOR_BITMAP);
        goto SETCURSOR_ERR_EXIT;
    }


    /******************************************************************/
    /* Synchronise between this thread of execution and the mouse     */
    /* pointer interrupt thread.                                      */
    /******************************************************************/
    disable_cursor();
    cursor_data.cursor_status |= CURSOR_EXCLUDED;


    /******************************************************************/
    /* Convert the supplied bitmaps to the format required by the h/w */
    /* The coloured icon defn. consists of 3 bitmaps, AND XOR and     */
    /* color. The AND mask precedes the XOR mask in memory.           */
    /* The bitmap details can be obtained from the bitmap header info.*/
    /*                                                                */
    /* These bitmaps are combined as follows to give the screen output*/
    /*                                                                */
    /*    XOR    AND    COLOR    RESULT                               */
    /*     1      1       x      Invert Screen                        */
    /*     0      0       x      x                                    */
    /*     0      1       x      Transparent                          */
    /*     1      0       x      x                                    */
    /*                                                                */
    /*  We want to convert this definition so we can simulate the     */
    /*  monochrome sprite by                                          */
    /*  - inverting all screen bits where the XOR mask is one         */
    /*  - bltting the colour bitmap to the screen using the AND mask  */
    /*    as a pattern with FgMix leavalone, BgMix source, ie. copy   */
    /*    the colour bitmap wherever the AND mask is 0                */
    /*                                                                */
    /*  We do this by copying the cursor data to the VRAM reserved    */
    /*  for it and enabling the colour cursor. On mouse interrupts    */
    /*  the code will use this to output the cursor                   */
    /*                                                                */
    /******************************************************************/


    /**************************************************************/
    /* 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  = MaskHeader->Info.Width - 1;
    BMCursorHeight = (MaskHeader->Info.Height / 2) - 1;

    /******************************************************************/
    /* First the AND ....                                             */
    /* Note that we have to do the AND and XOR masks separately       */
    /* because we now allow for coloured cursors which are smaller    */
    /* than the maximum sizes in DDT ie we cannot assume the XOR      */
    /* mask follows immediately after the AND mask in vram.           */
    /* Select the destination pixel map and set it up                 */
    /******************************************************************/

#ifdef _8514

 #ifdef   BPP24
    cursor_data.software_cursor.andmask++;
    cursor_data.software_cursor.andmask &= 0xfffffffe;
    cursor_data.software_cursor.xormask++;
    cursor_data.software_cursor.xormask &= 0xfffffffe;

    if ( DDT.fScreenFlags & USE_24BPP )
    {
       Shadow8514Regs.Color_1 =  0x00FFFFFF;
       Shadow8514Regs.Color_0 =  0;
       Copy24MonoToVRAM(MaskHeader->Bitmap, cursor_data.software_cursor.andmask,BMCursorWidth, BMCursorWidth, BMCursorHeight, ONE_BPP, 0);
       Copy24MonoToVRAM(MaskHeader->Bitmap + ((BMCursorWidth+1)/8 * (BMCursorHeight+1)), cursor_data.software_cursor.xormask,BMCursorWidth, BMCursorWidth, BMCursorHeight, ONE_BPP, 0);
    }
    else
    {
       CopyMaskToVRAM(MaskHeader->Bitmap, cursor_data.software_cursor.andmask, BMCursorWidth, BMCursorHeight, ONE_BPP);
       CopyMaskToVRAM(MaskHeader->Bitmap + ((BMCursorWidth+1)/8 * (BMCursorHeight+1)), cursor_data.software_cursor.xormask, BMCursorWidth, BMCursorHeight, ONE_BPP);
    }
 #else
    cursor_data.software_cursor.andmask++;
    cursor_data.software_cursor.andmask &= 0xfffffffe;
    CopyMaskToVRAM(MaskHeader->Bitmap, cursor_data.software_cursor.andmask, BMCursorWidth, BMCursorHeight, ONE_BPP);

    cursor_data.software_cursor.xormask++;
    cursor_data.software_cursor.xormask &= 0xfffffffe;
    CopyMaskToVRAM(MaskHeader->Bitmap + ((BMCursorWidth+1)/8 * (BMCursorHeight+1)), cursor_data.software_cursor.xormask, BMCursorWidth, BMCursorHeight, ONE_BPP);
 #endif

#else /* ~_8514 */

    CopyMemoryToVRAM( MaskHeader->Bitmap,
                      cursor_data.software_cursor.andmask,
                      BMCursorWidth,
                      BMCursorHeight,
                      ONE_BPP );


    CopyMemoryToVRAM( MaskHeader->Bitmap +
                           ((BMCursorWidth+1)/8 * (BMCursorHeight+1)),
                      cursor_data.software_cursor.xormask,
                      BMCursorWidth,
                      BMCursorHeight,
                      ONE_BPP );

#endif /* ~_8514 */

    /******************************************************************/
    /* Next copy the colour bitmap                                    */
    /******************************************************************/

    CopyMemoryToVRAM(ColourHeader->Bitmap,
                      cursor_data.software_cursor.bm,
                      BMCursorWidth,
                      BMCursorWidth,        /* height equals width */
                      DirectListEntry.Info.HWFormat);

#ifdef  _8514
    cursor_data.cursor_status |= CURSOR_COLOUR;
#endif

#if defined S3 | XGA
    /******************************************************************/
    /* if the last cursor was done via hardware then remove the h/w   */
    /* cursor and enable this colour cursor                           */
    /* Set the old cursor x coordinate to 0x8000 so MoveCursor knows  */
    /* it does not have to restore the screen under the old cursor    */
    /* (must be done before enabling the software cursor)             */
    /******************************************************************/
    if ( !(cursor_data.cursor_status & CURSOR_SOFTWARE) )
    {
        cursor_data.draw_sprite_flags = SPRITE_INVISIBLE;
        SetSpriteShape();
        cursor_data.software_cursor.coord.x = 0x8000;
    }
#endif

    /******************************************************************/
    /* we now have a software cursor                                  */
    /******************************************************************/
    cursor_data.cursor_status |= CURSOR_SOFTWARE;

    /******************************************************************/
    /* Store new hot spot position and width and height      //Raj    */
    /******************************************************************/
    cursor_data.hotspot_x = ArgCursorInfo->xHotspot;
    cursor_data.hotspot_y = ArgCursorInfo->yHotspot;

    #ifdef   BPP24
    if ( DDT.fScreenFlags & USE_24BPP )
    {
       cursor_data.cursor_width  = 3*ColourHeader->Info.Width;
    }
    else
    {
       cursor_data.cursor_width  = ColourHeader->Info.Width;
    }
    #else
    cursor_data.cursor_width  = ColourHeader->Info.Width;
    #endif
    cursor_data.cursor_height = ColourHeader->Info.Height;

    /******************************************************************/
    /* set the used portion to be the whole width of the cursor size  */
    /* (an optimization - done for mono software cursors - is to use  */
    /* the AND mask to reduce the cursor size to that which is        */
    /* actually used)                                                 */
    /******************************************************************/

    cursor_data.software_cursor.used.x = cursor_data.cursor_width;
    cursor_data.software_cursor.used.y = cursor_data.cursor_height;
    cursor_data.software_cursor.defnsize.x = cursor_data.cursor_width;
    cursor_data.software_cursor.defnsize.y = cursor_data.cursor_height;
    cursor_data.software_cursor.hwsize.x = cursor_data.cursor_width  - 1;
    cursor_data.software_cursor.hwsize.y = cursor_data.cursor_height - 1;

    /**************************************************************/
    /* 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;

    /******************************************************************/
    /* Defect 72344 - We must assume that the cursor state was        */
    /*                previously visible.                             */
    /******************************************************************/
    cursor_data.cursor_status |= CURSOR_VISIBLE;

    /******************************************************************/
    /* Switch the cursor back on again now we are finished with the   */
    /* hardware.                                                      */
    /******************************************************************/
    reenable_cursor();

#ifdef TMP                                                  
    cursor_data.cursor_status |= CURSOR_VISIBLE;
#endif 

    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 SEAMLESS
/**********************************************************************/
/* This is a dummy function (it is never called) that allows the      */
/* seamless         initialisation code to calculate the address and  */
/* length of code to enable the         VDMs addressibility to.       */
/* See also EndCursorCCode();.                                        */
/**********************************************************************/
VOID StartOfCursorCCode(VOID)
{
    /******************************************************************/
    /* Does nothing.                                                  */
    /******************************************************************/
}
#endif /* SEAMLESS */


/**********************************************************************/
/* ExcludeCursor checks whether the cursor is within the given        */
/* rectangle and, if so, removes it from the screen.                  */
/* The exclusion rectangle defines the area that is about to be drawn */
/* into.                                                              */
/* returns TRUE if cursor is excluded, FALSE if not                   */
/**********************************************************************/

USHORT eddm_ExcludeCursor(pDevPoint  ArgExclusionRect,
                          USHORT     CoordsType)

{
    DevRect     CurrentExclusionRect;
    ULONG       CalledFromBlt;
    ULONG       i;

    if ( !(cursor_data.cursor_status & CURSOR_VISIBLE) )
    {
        /**************************************************************/
        /* cursor is not currently displayed so no need to exclude    */
        /**************************************************************/
        return(FALSE);
    }

#ifndef _8514

    // Not sure if omitting this check for _8514 and S3 will get us into
    // trouble.  However, adding this check causes massive cursor corruption
    // problems when moving or resizing seamless windows.

    if (!pdc)                  /* 67953 */
    {                          /* 67953 */
        return(FALSE);         /* 67953 */
    }                          /* 67953 */
#endif

    /******************************************************************/
    /* save the special called from blt flag                          */
    /******************************************************************/
    CalledFromBlt = CoordsType & CALLED_FROM_BLT;

    if ( CalledFromBlt ||
         pdc->DCIBitmapType == BITMAP_IS_SCREEN )
    {
        /**************************************************************/
        /* reset the special called from blt flag                     */
        /**************************************************************/
        CoordsType &= ~CALLED_FROM_BLT;

        /**************************************************************/
        /* if we are not drawing to the screen then there is no need  */
        /* to do the exclusion. We do need to disable cursor updates  */
        /* however, to prevent MoveCursor using the hardware while    */
        /* the driver is doing other 'drawing' with it                */
        /**************************************************************/
        if (CoordsType == COORD_AI)
        {
            /**********************************************************/
            /* Coordinates are in AI format. Just need to copy them   */
            /* across to the CurrentExclusionRect.                    */
            /**********************************************************/
            CurrentExclusionRect[0].X = ArgExclusionRect[0].X;
            CurrentExclusionRect[1].X = ArgExclusionRect[1].X;
            CurrentExclusionRect[0].Y = ArgExclusionRect[0].Y;
            CurrentExclusionRect[1].Y = ArgExclusionRect[1].Y;
        }
        else
        {
            /**********************************************************/
            /* Coordinates are in device format. Need to copy them    */
            /* across the CurrentExclusionRect, converting them to AI */
            /* format as we go                                        */
            /**********************************************************/
            if (CoordsType & COORDS_ARE_WORDS)
            {
                /******************************************************/
                /* Each coordinate is one word long (16 bits).        */
                /******************************************************/
                CurrentExclusionRect[0].X = ArgExclusionRect[0].X +
                                                    pdc->DCIOrigin.X;
                CurrentExclusionRect[1].X = ArgExclusionRect[1].X +
                                                    pdc->DCIOrigin.X;
                CurrentExclusionRect[0].Y =  pdc->DCIConvFactor -
                                                 ArgExclusionRect[1].Y;
                CurrentExclusionRect[1].Y =  pdc->DCIConvFactor -
                                                 ArgExclusionRect[0].Y;
            }
            else
            {
                /******************************************************/
                /* Each coordinate is two words long (32 bits).       */
                /******************************************************/
                CurrentExclusionRect[0].X =
                      (SHORT)(*(pWcsRect)ArgExclusionRect)[0].X +
                                                    pdc->DCIOrigin.X;
                CurrentExclusionRect[1].X =
                      (SHORT)(*(pWcsRect)ArgExclusionRect)[1].X +
                                                    pdc->DCIOrigin.X;
                CurrentExclusionRect[0].Y =  pdc->DCIConvFactor -
                           (SHORT)(*(pWcsRect)ArgExclusionRect)[1].Y;
                CurrentExclusionRect[1].Y =  pdc->DCIConvFactor -
                           (SHORT)(*(pWcsRect)ArgExclusionRect)[0].Y;
            }
        }
    } /* bitmap is screen */


    /******************************************************************/
    /* if the cursor status  busy  flag is set then the movecursor    */
    /* interrupt code is about to, or is in the process of drawing    */
    /* the cursor at a new position. This means the cursor_ global    */
    /* variables may not contain a valid position and must not be     */
    /* used until the flag is reset. This thread can do no useful work*/
    /* until then so it suspends itself until drawing is complete     */
    /* using DosSleep with a zero timeout which causes the thread to  */
    /* give up the rest of its timeslice to another thread of an equal*/
    /* By resetting the VISIBLE flag we can ensure that MoveCursor    */
    /* will exit quickly and not stick in a loop constantly           */
    /* redrawing and locking out this thread                          */
    /*                                                                */
    /* To have got here the VISIBLE flag must have been set, so as    */
    /* long as we set it again later we will do no lasting damage     */
    /******************************************************************/
    cursor_data.cursor_status &= ~CURSOR_VISIBLE;
    eddm_Interrupts_Off();
    while (cursor_data.cursor_status & CURSOR_BUSY)
    {
        eddm_Interrupts_On();
#ifdef SEAMLESS
        for (i = 0; i < 1000; i++)
        {
            /**********************************************************/
            /* Loop around a bit before trying again. (Windows VDM    */
            /* can not make calls to DosSleep).                       */
            /**********************************************************/
        }
#else
        DosSleep(0L);
#endif

        eddm_Interrupts_Off();
    }

    /******************************************************************/
    /* We need to disable MoveCursor drawing regardless of whether    */
    /* or not we actually exclude the cursor. This ensures MoveCursor */
    /* does not use the hardware while another part of the driver is  */
    /* also doing so.                                                 */
    /*                                                                */
    /* This can be achieved by setting the CURSOR_HWINUSE bit in the  */
    /* cursor status byte to indicate to movecursor that a drawing    */
    /* operation is occuring                                          */
    /*                                                                */
    /* We also set the VISIBLE flag again now that we know MoveCursor */
    /* is not executing                                               */
    /*                                                                */
    /* Having done all that we can reenable interrupts knowing that   */
    /* MoveCursor will always exit without drawing                    */
    /******************************************************************/
    cursor_data.cursor_status |= ( CURSOR_HWINUSE | CURSOR_VISIBLE );
    eddm_Interrupts_On();


    /******************************************************************/
    /* if the DC is direct we will need to remove the cursor if it    */
    /* coincides with the thing being drawn                           */
    /******************************************************************/
    if ( (CalledFromBlt || pdc->DCIBitmapType == BITMAP_IS_SCREEN) &&
         (CurrentExclusionRect[0].X < (SHORT)
              (cursor_data.cursor_x - cursor_data.hotspot_x +
                                cursor_data.software_cursor.used.x)) &&
         (CurrentExclusionRect[0].Y < (SHORT)
               (cursor_data.cursor_y + cursor_data.hotspot_y + 1)) &&
         (CurrentExclusionRect[1].X  >= (SHORT)
                   (cursor_data.cursor_x - cursor_data.hotspot_x)) &&
         (CurrentExclusionRect[1].Y >= (SHORT)
            (cursor_data.cursor_y + cursor_data.hotspot_y + 1 -
             cursor_data.software_cursor.used.y)))
    {
        /**************************************************************/
        /* get rid of the cursor currently displayed                  */
        /**************************************************************/
        remove_software_cursor();

        /**************************************************************/
        /* flag the exclusion                                         */
        /**************************************************************/
        cursor_data.cursor_status |= CURSOR_EXCLUDED;

        return(TRUE);

    } /* need to remove cursor */
    else
    {
        return(FALSE);
    }
}





/**********************************************************************/
/* disable_cursor is similar to exclude cursor in that it waits       */
/* for MoveCursor to be not executing then disables cursor drawing.   */
/* However, it does not do any exclusion. This should be called       */
/* before any hardware usage when the cursor is software but          */
/* exclusion is not needed (not drawing to screen)                    */
/**********************************************************************/

VOID disable_cursor(VOID)
{
    ULONG   i;

    /******************************************************************/
    /* only need to disable cursor drawing if the cursor is visible   */
    /* (if it's not visible then it wo'n't be drawn therefore the     */
    /* hardware will never be used anyway)                            */
    /******************************************************************/
    if (cursor_data.cursor_status & CURSOR_VISIBLE)
    {
        /**************************************************************/
        /* if the cursor status BUSY flag is set then the movecursor  */
        /* interrupt code is about to, or is in the process of        */
        /* drawing the cursor at a new position. This means the       */
        /* hardware is unavailable until the flag is reset. This      */
        /* thread can do no useful work until then, so it suspends    */
        /* itself until drawing is complete using DosSleep with a     */
        /* zero timeout which causes the thread to give up the rest   */
        /* of its timeslice to another thread of an equal or higher   */
        /* priority                                                   */
        /**************************************************************/
        cursor_data.cursor_status &= ~CURSOR_VISIBLE;
        eddm_Interrupts_Off();
        while (cursor_data.cursor_status & CURSOR_BUSY)
        {
            eddm_Interrupts_On();
#ifdef SEAMLESS
            for (i = 0; i < 1000; i++)
            {
                /**********************************************************/
                /* Loop around a bit before trying again. (Windows VDM    */
                /* can not make calls to DosSleep).                       */
                /**********************************************************/
            }
#else
            DosSleep(0L);
#endif
            eddm_Interrupts_Off();
        }

        /**************************************************************/
        /* MoveCursor is not executing now and cannot until           */
        /* interrupts are enabled.                                    */
        /* we can ensure that the MoveCursor code does not use the    */
        /* H/W by setting the HWINUSE flag                            */
        /**************************************************************/
        cursor_data.cursor_status |= ( CURSOR_HWINUSE | CURSOR_VISIBLE );
        eddm_Interrupts_On();
    }

} /* disable_cursor */

/**********************************************************************/
/* reenabling the cursor really means that we allow the MoveCursor    */
/* code to have control of the cursor again                           */
/* We need to unexclude any exclude cursor                            */
/*            release the hardware                                    */
/*            force a redraw (either immediate or lazy)               */
/**********************************************************************/
VOID reenable_cursor(VOID)
{
    /******************************************************************/
    /* free the hardware                                              */
    /******************************************************************/
    cursor_data.cursor_status &= ~CURSOR_HWINUSE;

    /******************************************************************/
    /* unexclude the cursor by allowing a redraw on the next interrupt*/
    /******************************************************************/
    if ( cursor_data.cursor_status & CURSOR_EXCLUDED )
    {
        eddm_Interrupts_Off();
        cursor_data.cursor_status =
                (cursor_data.cursor_status | CURSOR_REDRAW) &
                                                       ~CURSOR_EXCLUDED;
        eddm_Interrupts_On();
    }

    /******************************************************************/
    /* if the cursor was moved during the period in which the H/W     */
    /* was in use then we should not rely on lazy redraw              */
    /* - force a redraw now                                           */
    /******************************************************************/
/**********************************************************************/
/* Currently there is no mechanism to call the move cursor routine    */
/* internally.  This is not very important since we rarely have a     */
/* software cursor anyway (except on P75s).  The effect is not that   */
/*     anyway since PMDD does a check cursor every 1/3 of a second.   */
/* If this is ever added as an internal call then there is no need    */
/* for a callgate because we know we have SW cursor and so the redraw */
/* will not have to use IOPL to reposition the sprite.  This means    */
/* that seamless         will also still work.  (Seamless VDM threads */
/* can not go through ring transitions).                              */
/**********************************************************************/
//    if (cursor_data.cursor_status & CURSOR_MOVED)
//    {
//        cursor_data.cursor_status |= CURSOR_REDRAW;
//                                            /* ensure cursor is drawn */
//        MoveCursor(0x8000,0x8000);
//    }
}

#ifdef SEAMLESS
/**********************************************************************/
/* This is a dummy function (it is never called) that allows the      */
/* seamless         initialisation code to calculate the address and  */
/* length of code to enable the         VDMs addressibility to.       */
/* See also StartCursorCCode();.                                      */
/**********************************************************************/
VOID EndOfCursorCCode(VOID)
{
    /******************************************************************/
    /* Does nothing.                                                  */
    /******************************************************************/
}
#endif /* SEAMLESS */

/**********************************************************************/
/* This routine will update the cursor exclude region. This only      */
/* applies if we are using a software cursor. The next time           */
/* MoveCursor is called, it will check if the cursor is in this       */
/* region. If it is then it will not be drawn.                        */
/**********************************************************************/
VOID UpdateXcludeRegion(RECTL XcludeRegion)
{

  DevRect     ExcludeRect;

  cursor_data.software_cursor.XcludeRect.xLeft = XcludeRegion.xLeft;
  cursor_data.software_cursor.XcludeRect.yTop = XcludeRegion.yTop;
  cursor_data.software_cursor.XcludeRect.xRight = XcludeRegion.xRight;
  cursor_data.software_cursor.XcludeRect.yBottom = XcludeRegion.yBottom;

  if(!softDrawInUse ) {
     /**************************************************************/
     /* Exclude the cursor from the target rectangle.              */
     /**************************************************************/
     ExcludeRect[0].X = (SHORT)XcludeRegion.xLeft;
     ExcludeRect[0].Y = (SHORT)XcludeRegion.yTop;
     ExcludeRect[1].X = (SHORT)XcludeRegion.xRight;
     ExcludeRect[1].Y = (SHORT)XcludeRegion.yBottom;
     eddm_ExcludeCursor(ExcludeRect, COORD_AI | CALLED_FROM_BLT);
  }

  cursor_data.cursor_status |= CURSOR_XREGION;

}

