/*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.                                */
/*                                                                           */
/*****************************************************************************/
/**************************************************************************
 *
 * SOURCE FILE NAME = VVVTEXT.C
 *
 * DESCRIPTIVE NAME = Virtual Video VTEXT in Gale VDM Processing
 *
 *
 * VERSION = V2.0
 *
 * DATE      03/08/93
 *
 * DESCRIPTION  This module contains the VVD's VTEXT support code.
 *
 * FUNCTIONS
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/

#define INCL_MI
#include <mvdm.h>
#include <vvd.h>
#include "vvdp.h"
#include "vvstub.h"
#ifdef VDDSTRICT
MODNAME = __FILE__;
#endif

extern ULONG flVVD;

extern UCHAR DBCSVector[4];

#define pVtextStub              GaleSBCS
#define StubAccess(type, off)   (type)(VDMData.GaleData.pVtextStub + (off))

#define BIT_DISABLE_$DISP       0x0040

#define VTEXT_DEVICE_NAME           "$IBMADSP"
#define VTEXT_DEVICE_NAME_OFFSET    0x000a

#pragma  BEGIN_SWAP_DATA
#ifdef  SVGA
extern ULONG ulSVGAAdapterType;
#endif  //SVGA
extern BOOL  (PRIVENTRY *VtextNotify)();
#pragma  END_SWAP_DATA

#pragma BEGIN_SWAP_CODE

#ifdef  VTEXT

/***LP  VVInt10VtextHook()
 *
 *  This subroutine processes INT 10H post hook.
 *
 *  ENTRY
 *      pRefData -> not used, none allocated
 *      pcrf -> VDM register frame (CRF)
 *  EXIT
 *      None
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      VDM Task-time
 *
 *  PSEUDO-CODE                                     REFERENCES
 */

VOID HOOKENTRY VVInt10VtextHook(PVOID pRefData, register PCRF pcrf)
{
    register USHORT ax, ah, al;

    VDHPopStack(sizeof(WORD), &pcrf->crf_eip);
    VDHPopStack(sizeof(WORD), &pcrf->crf_cs);

    if ((VDMData.GaleData.flVtext & VDMV_PTR_V86_EXECUTING) ||
        (VDMData.GaleData.flVtext & VDMV_REDRAW_SCREEN))
        return;

    ax = *StubAccess(PUSHORT, VTEXT_INT10_STAT_AX);
    ah = ax >> 8;
    al = ax & 0xff;

    if ((ah == 0) || (ax == 0x1118)) {
        vvCheckSetModeVtext(pcrf);

        if (VDMData.GaleData.flVtext & VDMV_SUPPORTED_TEXT_MODE)
            vvUpdateScreenState(CURRENT_VDM, TRUE);
    }

    if (VDMData.flVDMVideo & VDM_FGND) {
        if (VDMData.GaleData.flVtext & VDMV_DELAYED_REDRAW_SCREEN) {
            vvRedrawVtext(pcrf);
            VDMData.GaleData.flVtext &= ~VDMV_DELAYED_REDRAW_SCREEN;
        }
        if (VDMData.GaleData.flVtext & VDMV_DELAYED_UPDATE_FLAG) {
            vvSet$DispDrawingFlag(CURRENT_VDM, TRUE);
            VDMData.GaleData.flVtext &= ~VDMV_DELAYED_UPDATE_FLAG;
        }

        return;
    }

    if (VDMData.GaleData.flVtext & VDMV_DELAYED_UPDATE_FLAG) {
        vvSet$DispDrawingFlag(CURRENT_VDM, FALSE);
        VDMData.GaleData.flVtext &= ~VDMV_DELAYED_UPDATE_FLAG;
    }

    if ((ah == 0x00) ||             /* Set Video Mode                   */
        (ax == 0x1118)) {           /* Set Row Count                    */
        if (VDMData.GaleData.flVtext & VDMV_SUPPORTED_TEXT_MODE) {
            vvSet$DispDrawingFlag(CURRENT_VDM, FALSE);
        }
    } else if (VDMData.GaleData.flVtext & VDMV_SUPPORTED_TEXT_MODE) {
        switch (ah) {
        case 0x01:                  /* Set Cursor Type                  */
        case 0x02:                  /* Set Cursor Position              */
            vvUpdateCursorDataVtext(CURRENT_VDM);
            break;

        case 0x06:                  /* Scroll Active Page Up            */
        case 0x07:                  /* Scroll Active Page Down          */
        case 0x09:                  /* Write Char/Attr at Curr Csr Pos  */
        case 0x0a:                  /* Write Char at Curr Csr Pos       */
        case 0xff:                  /* Update Video Display             */
            VDMData.GaleData.flVtext |= VDMV_LVB_UPDATED;
            break;

        case 0x0e:                  /* Write TTY to Active Page         */
        case 0x13:                  /* Write/Read String                */
            vvUpdateCursorDataVtext(CURRENT_VDM);
            VDMData.GaleData.flVtext |= VDMV_LVB_UPDATED;
            break;

        default:
            break;
        }
    }

    /*** pointer erase request is called from VVSetBgnd during V86 ***/
    /*** int 10h routine.                                          ***/
    if (VDMData.GaleData.flVtext & VDMV_PTR_REQ_ERASE_SP2) {
        VDMData.GaleData.flVtext &= ~VDMV_PTR_REQ_ERASE_SP2;
        vvPtrSetupEraseVtext();
    }
}

/***LP  VVInt10VtextPreHook()
 *
 *  This subroutine processes INT 10H pre hook.
 *
 *  ENTRY
 *      pRefData -> not used, none allocated
 *      pcrf -> VDM register frame (CRF)
 *  EXIT
 *      None
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      VDM Task-time
 *
 *  PSEUDO-CODE                                     REFERENCES
 */

VOID HOOKENTRY VVInt10VtextPreHook(PVOID pRefData, register PCRF pcrf)
{
    VDHPopStack(sizeof(WORD), &pcrf->crf_eip);
    VDHPopStack(sizeof(WORD), &pcrf->crf_cs);

    if ((VDMData.GaleData.flVtext & VDMV_GET_LVB) ||
        (VDMData.GaleData.flVtext & VDMV_GET_EXT_INFO))
        return;

    if (VDMData.GaleData.pVtextLVB == NULL) {

        /*** push int 10h ah=feh 'Get Video Buffer' ***/
        VDMData.GaleData.flVtext |= VDMV_GET_LVB;
        VDHPushRegs(VDHREG_GENERAL);
        AH(pcrf) = 0xfe;
        ES(pcrf) = 0xb800;
        DI(pcrf) = 0x0000;

        VDHPushInt(0x10);
        VDHArmReturnHook(VDMData.GaleData.hhookVtextReturn,
                         VDHARH_RECURSIVE_IRET);
    }
}

/***LP  vvCheckDispDD()
 *
 *  This subroutine pushes int 15h 'Get BIOS Type' to check
 *  the installation of $DISP.SYS.
 *
 *  ENTRY
 *      pcrf -> VDM register frame (ignored)
 *  EXIT
 *      None
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      VDM Task-time
 *
 *  PSEUDO-CODE                                     REFERENCES
 */

VOID PRIVENTRY vvCheckDispDD(PCRF pcrf)
{
    if (VDMData.flVDMGale &&
        !(VDMData.GaleData.flVtext & VDMV_VTEXT_INSTALLED)) {

        /*** check $DISP.SYS installation using int 15h 'Get BIOS Type ' ***/
        VDHPushRegs(VDHREG_GENERAL);
        AX(pcrf) = 0x4900;
        VDHPushInt(0x15);
        VDHArmReturnHook(VDMData.GaleData.hhookVtextReturn,
                         VDHARH_RECURSIVE_IRET);
        VDMData.GaleData.flVtext |= VDMV_CHECK_VTEXT;
        VDMData.GaleData.flVtext &= ~VDMV_PROCESSED_BY_MYSELF;
    }
}

/***LP  VVCheckVtextReturn()
 *
 *  This subroutine receives the result from $DISP.SYS.
 *
 *  ENTRY
 *      p - (ignored)
 *      pcrf -> VDM register frame (ignored)
 *  EXIT
 *      None
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      VDM Task-time
 *
 *  PSEUDO-CODE                                     REFERENCES
 */

VOID HOOKENTRY VVCheckVtextReturn(PVOID p, PCRF pcrf)
{
    if (VDMData.GaleData.flVtext & VDMV_CHECK_VTEXT) {

        /*** check $disp.sys installation ***/
        if (!(VDMData.GaleData.flVtext & VDMV_PROCESSED_BY_MYSELF)) {
            VDMData.GaleData.flVtext |= VDMV_VTEXT_INSTALLED
                                     |  VDMV_VTEXT_INITIALIZING;

            VDMData.GaleData.flVtext &= ~VDMV_VTEXT_CALLING;

            VDMData.flVDMGale = FALSE;

            /*** install stub int 10h routine ***/
            memcpy(VDMData.GaleData.pVtextStub, VtextStubEntry,
                   VTEXT_STUB_LENGTH);

            /*** set original $DISP.SYS entry ***/
            *StubAccess(PULONG, VTEXT_INT10_ORG_ADDR1) =
            *StubAccess(PULONG, VTEXT_INT10_ORG_ADDR2) =
                        (ULONG)VDMBase.rb_avpIVT[0x10];

            /*** set DBCS vector ***/                                   //J-TS0811
            *StubAccess(PULONG, VTEXT_PTR_PARAM_DBCSVECT) =             //J-TS0811
                        *(ULONG *)DBCSVector;                           //J-TS0811

            /*** set int 10h interrupt vector to pre hook entry ***/
            VDMBase.rb_avpIVT[0x10] =
                    VPFROMP(StubAccess(PVOID, VTEXT_INT10_PREHOOK_ENTRY));

            /*** set video mdoe ***/
            VDMData.ulBIOSMode = 0x03;
            vvSetSupportedModeFlag(TRUE);
            vvUpdateAll(CURRENT_VDM, FALSE);

            /*** set post hook ***/
            VDMData.GaleData.pBreakPointAddr =
                        VDHArmBPHook(VDMData.GaleData.hhookVtextHook);
            *StubAccess(VPVOID *, VTEXT_INT10_HOOK_ADDR1) =
                        VDMData.GaleData.pBreakPointAddr;

            /*** set pre hook ***/
            *StubAccess(VPVOID *, VTEXT_INT10_HOOK_ADDR2) =
                        VDHArmBPHook(VDMData.GaleData.hhookVtextPreHook);
        }
        VDMData.GaleData.flVtext &= ~VDMV_CHECK_VTEXT;

        VDHPopRegs(VDHREG_GENERAL);

    } else if (VDMData.GaleData.flVtext & VDMV_GET_LVB) {

        /*** get LVB addr in $disp.sys ***/
        if ((ES(pcrf) != 0xb800) || (DI(pcrf) != 0x0000)) {

            /*** get LVB address from $DISP.SYS ***/
            VDMData.GaleData.pVtextLVB = (PBYTE)((ES(pcrf) << 4) + DI(pcrf));

            /*** push 'get extended infomation' interrupt ***/
            AX(pcrf) = 0x5010;
            VDHPushInt(0x15);
            VDHArmReturnHook(VDMData.GaleData.hhookVtextReturn,
                             VDHARH_RECURSIVE_IRET);
            VDMData.GaleData.flVtext |= VDMV_GET_EXT_INFO;

        } else {

            VDHPopRegs(VDHREG_GENERAL);
        }

        VDMData.GaleData.flVtext &= ~VDMV_GET_LVB;

    } else if (VDMData.GaleData.flVtext & VDMV_GET_EXT_INFO) {

        VDMData.GaleData.flVtext &= ~VDMV_VTEXT_INITIALIZING;

        /*** get VTEXT extended infomation ***/
        if (!(FL(pcrf) & F_CARRY)) {

            /*** supported ($DISP.SYS for VTEXT) ***/
            VDMData.GaleData.pVtextExtInfo = (PVTEXTEXTINFO)((ES(pcrf) << 4)
                                                            + BX(pcrf));
            /*** update initial screen state ***/
            vvUpdateScreenState(CURRENT_VDM, TRUE);

        } else {

            /*** not supported (original $DISP.SYS) ***/
            VDMData.GaleData.pVtextExtInfo = NULL;
        }

            /*** check background access ***/
            if (!(VDMData.flVDMVideo & VDM_FGND))
                vvSet$DispDrawingFlag(CURRENT_VDM, FALSE);

        /*** re-set int 10h interrupt vector to post hook entry ***/
        VDMBase.rb_avpIVT[0x10] =
                VPFROMP(StubAccess(PVOID, VTEXT_INT10_HOOK_ENTRY));
        VDHFreeHook(VDMData.GaleData.hhookVtextPreHook);

        VDMData.GaleData.flVtext &= ~VDMV_GET_EXT_INFO;

        VDHPopRegs(VDHREG_GENERAL);
    }
}

/***LP  vvCheckForDirtyLVBVtext
 *
 *  This subroutine checks LVB updating
 *
 *  ENTRY
 *      hvdm == VDM handle
 *      fl   == Event flags to post if dirty
 *  EXIT
 *      TRUE if VDM's LVB was dirty, FALSE if not
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      Task-time
 *
 *  PSEUDO-CODE                                     REFERENCES
 */

BOOL PRIVENTRY vvCheckForDirtyLVBVtext(HVDM hvdm, FLAGS fl)
{
    register PVDMDATA pvd = pVDMData(hvdm);
    FLAGS flDirty = FALSE;
    ULONG pages;

    if (((flVVD & VVD_PMBGND) && (pvd->flVDMVideo & VDM_PMWINDOWED)) || //J-TS0825
        ((pvd->flVDMVideo & (VDM_WINDOWED | VDM_MINIMIZED)) != VDM_WINDOWED))   //J-TS0825
        return flDirty;                                             //J-TS0825

    if (pvd->GaleData.flVtext & VDMV_LVB_UPDATED) {
        pages = (pvd->vvMode.vvm_nRows * pvd->vvMode.vvm_nCols * 2 + 0xfff)
              / 0x1000;
        flDirty = (1 << pages) - 1;
        vvAddEvent(hvdm, VVDEVENT_LVB, SSToDS(&flDirty), fl);
        pvd->GaleData.flVtext &= ~VDMV_LVB_UPDATED;
    }

    return flDirty;
}

/***LP  vvMapVtextPVB
 *
 *  This subroutine checks page fault at B80000
 *
 *  ENTRY
 *      pvdmFault -> linear address within the VDM
 *  EXIT
 *      EMULATED
 *          TRUE
 *      NOT EMULATED
 *          FALSE (pass control to next VDD and/or ROM)
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      Task-time
 *
 *  PSEUDO-CODE                                     REFERENCES
 */

BOOL PRIVENTRY vvMapVtextPVB(PVDM pvdmFault)
{
    register int i;
    register USHORT *p;
    VDHMAPTARGET tgt;
    VDHMAPSOURCE src;

    if (!(VDMData.flVDMVideo & VDM_FGND) &&
        ((VDMData.GaleData.flVtext & VDMV_VTEXT_CALLING) ||
         ((VDMData.GaleData.flVtext & VDMV_SUPPORTED_TEXT_MODE) &&
          (*StubAccess(PUCHAR, VTEXT_INT10_STAT_INFLAG))))) {
        vvMapPage(pvdmFault, NULL, ALL_PLANES,
                  BANK0, VDHMT_BLACK_HOLE);
        return TRUE;
    }

    if ((pvdmFault < (PVDM)0xb8000) || ((PVDM)0xb8fff < pvdmFault))
        return FALSE;

    if (!VDMData.flVDMGale ||
        (VDMData.GaleData.flVtext & VDMV_VTEXT_INSTALLED))
        return FALSE;

    if (VDMBase.rb_bVMode != 0x03)
        return FALSE;

                    /* allocate & initialize dummy PVB at B8000 */
    if (!(VDMData.GaleData.pVtextPVB
                    = VDHAllocPages(NULL, 1L, VDHAP_SWAPPABLE)))
        return FALSE;

    for (i = 0, p = (PUSHORT)VDMData.GaleData.pVtextPVB; i < 2048; i++)
        *p++ = 0x0720;

    src.vdhms_laddr = (ULONG)VDMData.GaleData.pVtextPVB;
    src.vdhms_hobj  = 0;
    tgt.vdhmt_laddr = 0xb8000;
    tgt.vdhmt_cpg   = 1;
    tgt.vdhmt_hmap  = 0;
    VDHMapPages(SSToDS(&src), SSToDS(&tgt), VDHMT_LINEAR);

    return TRUE;
}

/***LP  vvUnmapVtextPVB
 *
 *  This subroutine checks page mapping at B80000 and free the memory
 *
 *  ENTRY
 *      None
 *  EXIT
 *      EMULATED
 *          TRUE
 *      NOT EMULATED
 *          FALSE (pass control to next VDD and/or ROM)
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      Task-time
 *
 *  PSEUDO-CODE                                     REFERENCES
 */

VOID PRIVENTRY vvUnmapVtextPVB()
{
    VDHMAPTARGET tgt;

    if (!VDMData.GaleData.pVtextPVB)
        return;

    tgt.vdhmt_laddr = 0xb8000;
    tgt.vdhmt_cpg   = 1;
    tgt.vdhmt_hmap  = 0;
    VDHMapPages(NULL, SSToDS(&tgt), VDHMT_INVALID);
    VDHFreePages(VDMData.GaleData.pVtextPVB);
    VDMData.GaleData.pVtextPVB = NULL;
}

/***LP  vvCheckSetModeVtext
 *
 *  This subroutine checks set mode number
 *
 *  ENTRY
 *      pcrf    -> VDM register frame
 *  EXIT
 *      EMULATED
 *          TRUE
 *      NOT EMULATED
 *          FALSE (pass control to next VDD and/or ROM)
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      Task-time
 *
 *  PSEUDO-CODE                                     REFERENCES
 */

VOID PRIVENTRY vvCheckSetModeVtext(PCRF pcrf)
{
    if (!(VDMData.GaleData.flVtext & VDMV_VTEXT_INITIALIZING) &&
        !(VDMData.GaleData.flVtext & VDMV_REDRAW_SCREEN)) {
        if (*StubAccess(PUCHAR, VTEXT_INT10_STAT_AX + 1) == 0x00) { /* Set mode? */
            VDMData.ulBIOSMode = *StubAccess(PUCHAR, VTEXT_INT10_STAT_AX)
                               & ~BIOSVINFO_DONTCLEAR;
                                                        /* Set row count? */
        } else if (*StubAccess(PUSHORT, VTEXT_INT10_STAT_AX) == 0x1118) {
            VDMData.ulBIOSMode = VDMBase.rb_bVMode;
        }

        switch (VDMData.ulBIOSMode) {
        case 0x03:
        case 0x70:
        case 0x71:
        case 0x73:
            vvSetSupportedModeFlag(TRUE);
            break;

        default:
            vvSetSupportedModeFlag(FALSE);
            break;
        }
#ifdef  SVGA
        if ((ulSVGAAdapterType == S3_ADAPTER) &&
            !(VDMData.flVDMVideo & VDM_FGND)) {
            if (VDMData.GaleData.flVtext & VDMV_SUPPORTED_TEXT_MODE)        //J-TS0826
                VDMData.awreg8514Data[WREG_ADVCTRL] |=  ADVCTRL_VGADISABLE; //J-TS0826
            else                                                            //J-TS0826
                VDMData.awreg8514Data[WREG_ADVCTRL] &= ~ADVCTRL_VGADISABLE; //J-TS0826
        }
#endif  //SVGA

        vvSet$DispDrawingFlag(CURRENT_VDM, VDMData.flVDMVideo & VDM_FGND);
        vvUpdateAll(CURRENT_VDM, TRUE);
    }
}

/***LP  vvCheckCallerVtext
 *
 *  This subroutine checks the caller of set mode
 *
 *  ENTRY
 *      pcrf    -> VDM register frame
 *  EXIT
 *      None
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      Task-time
 *
 *  PSEUDO-CODE                                     REFERENCES
 */

VOID PRIVENTRY vvCheckCallerVtext(PCRF pcrf)
{
    ULONG *p, *q;

    /* get device header */
    p = (ULONG *)((SS(pcrf) << 4) | VTEXT_DEVICE_NAME_OFFSET);
    q = (ULONG *)VTEXT_DEVICE_NAME;

    if ((p[0] == q[0]) && (p[1] == q[1]))
        VDMData.GaleData.flVtext |= VDMV_VTEXT_CALLING;
    else
        VDMData.GaleData.flVtext &= ~VDMV_VTEXT_CALLING;
}

/***LP  vvFgndContextVtext
 *
 *  This subroutine redraws the screen during the screen switch from BG to FG
 *
 *  ENTRY
 *      pcrf -> VDM register frame
 *  EXIT
 *      EMULATED
 *          TRUE
 *      NOT EMULATED
 *          FALSE (pass control to next VDD and/or ROM)
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      Task-time
 *
 *  PSEUDO-CODE                                     REFERENCES
 */

VOID PRIVENTRY vvFgndContextVtext(PCRF pcrf)
{
    if (!(VDMData.GaleData.flVtext & VDMV_REDRAW_AGAIN) &&
        (*StubAccess(PUCHAR, VTEXT_INT10_STAT_INFLAG))) {
        /*** Now the control is in $DISP.SYS ***/
        VDMData.GaleData.flVtext |= VDMV_DELAYED_REDRAW_SCREEN
                                 |  VDMV_DELAYED_UPDATE_FLAG;
    } else {
        /*** Now the control isn't in $DISP.SYS ***/
        vvRedrawVtext(pcrf);
        vvSet$DispDrawingFlag(CURRENT_VDM, TRUE);
    }
}

/***LP  vvBgndContextVtext
 *
 *  This subroutine resets the hardware update flag of $DISP.SYS.
 *
 *  ENTRY
 *      pcrf -> VDM register frame
 *  EXIT
 *      EMULATED
 *          TRUE
 *      NOT EMULATED
 *          FALSE (pass control to next VDD and/or ROM)
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      Task-time
 *
 *  PSEUDO-CODE                                     REFERENCES
 */

VOID PRIVENTRY vvBgndContextVtext(PCRF pcrf)
{
    if (*StubAccess(PUCHAR, VTEXT_INT10_STAT_INFLAG)) {
        /*** Now the control is in $DISP.SYS ***/
        VDMData.GaleData.flVtext |= VDMV_DELAYED_UPDATE_FLAG;

    } else {
        /*** Now the control isn't in $DISP.SYS ***/
        vvSet$DispDrawingFlag(CURRENT_VDM, FALSE);
    }
}

/***LP  vvRedrawVtext
 *
 *  This subroutine really redraws the screen.
 *
 *  ENTRY
 *      pcrf -> VDM register frame
 *  EXIT
 *      EMULATED
 *          TRUE
 *      NOT EMULATED
 *          FALSE (pass control to next VDD and/or ROM)
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      Task-time
 *
 *  PSEUDO-CODE                                     REFERENCES
 */

VOID PRIVENTRY vvRedrawVtext(PCRF pcrf)
{
    FPFN addr;

    if (VDMData.GaleData.flVtext & VDMV_SUPPORTED_TEXT_MODE) {

        /*** If the redraw routine is alread called ***/
        if (VDMData.GaleData.flVtext & VDMV_REDRAW_SCREEN) {
            VDMData.GaleData.flVtext |= VDMV_REDRAW_AGAIN;
            return;
        }

        /*** Push all VDM's general-purpose registers ***/
        VDHPushRegs(VDHREG_GENERAL);

        /*** Setup parameter ***/
        *StubAccess(PUCHAR,  VTEXT_REDRAW_MODE) = VDMData.ulBIOSMode;
        *StubAccess(PUSHORT, VTEXT_REDRAW_ROW ) = VDMData.vvMode.vvm_nRows;

        VDMData.GaleData.flVtext |= VDMV_REDRAW_SCREEN;

        /*** set return hook */
        VDHArmReturnHook(VDMData.GaleData.hhookVtextRedrawReturn,
                         VDHARH_CSEIP_HOOK);

        /* push far call to V86 redraw routine */
        SEGMENTOF32(addr) = (ULONG)VDMData.GaleData.pVtextStub >> 4;
        OFFSETOF32(addr)  = VTEXT_REDRAW_ENTRY;
        VDHPushFarCall(addr);
    }
}

/***LP  VVVtextRedrawReturn()
 *
 *  This subroutine receives the result from screen redraw.
 *
 *  ENTRY
 *      p - (ignored)
 *      pcrf -> VDM register frame (ignored)
 *  EXIT
 *      None
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      VDM Task-time
 *
 *  PSEUDO-CODE                                     REFERENCES
 */

VOID HOOKENTRY VVVtextRedrawReturn(PVOID p, PCRF pcrf)
{
    /*** restore V86 registers ***/
    VDHPopRegs(VDHREG_GENERAL);

    VDMData.GaleData.flVtext &= ~VDMV_REDRAW_SCREEN;

    /*** If 2nd screen switch occures, redraw screen routine  ***/
    /*** must be called again.                                ***/
    if (VDMData.GaleData.flVtext & VDMV_REDRAW_AGAIN) {
        VDMData.GaleData.flVtext &= ~VDMV_REDRAW_AGAIN;
        vvRedrawVtext(pcrf);
    }
}

/***LP  vvSet$DispDrawingFlag
 *
 *  This subroutine set/reset $DISP drawing flag just before LVB.
 *
 *  ENTRY
 *      hvdm  == VDM handle
 *      flSet == TRUE  : Permit to update hardware
 *               FALSE : Inhibit to update hardware
 *  EXIT
 *      None
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      Task-time
 *
 *  PSEUDO-CODE                                     REFERENCES
 */

VOID PRIVENTRY vvSet$DispDrawingFlag(HVDM hvdm, BOOL flSet)
{
    register PVDMDATA pvd = pVDMData(hvdm);

    if (!(pvd->GaleData.flVtext & VDMV_VTEXT_INITIALIZING)) {
        if (flSet)
            *(PWORD)(pvd->GaleData.pVtextLVB - 2) &= ~BIT_DISABLE_$DISP;
        else
            *(PWORD)(pvd->GaleData.pVtextLVB - 2) |= BIT_DISABLE_$DISP;
    }
}

/***LP  vvSetSupportedModeFlag
 *
 *  This subroutine set/reset VDMV_SUPPORTED_TEXT_MODE flag.
 *
 *  ENTRY
 *      flSet == TRUE  : set   VDMV_SUPPORTED_TEXT_MODE
 *               FALSE : reset VDMV_SUPPORTED_TEXT_MODE
 *  EXIT
 *      None
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      Task-time
 *
 *  PSEUDO-CODE                                     REFERENCES
 */

VOID PRIVENTRY vvSetSupportedModeFlag(BOOL flSet)
{
    if (flSet)
        VDMData.GaleData.flVtext |=  VDMV_SUPPORTED_TEXT_MODE;
    else
        VDMData.GaleData.flVtext &= ~VDMV_SUPPORTED_TEXT_MODE;

    if (VtextNotify)
        (* VtextNotify)(flSet);
}

/***LP  vvGetRowCountVtext
 *
 *  This subroutine returns the current row count.
 *
 *  ENTRY
 *      hvdm  == VDM handle
 *  EXIT
 *      Number of current rows
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      Task-time
 *
 *  PSEUDO-CODE                                     REFERENCES
 */

ULONG PRIVENTRY vvGetRowCountVtext(HVDM hvdm)
{
    register PVDMDATA pvd = pVDMData(hvdm);
    ULONG rows;
    PVTEXTMODETABLE pmode;
    PVTEXTEXTPARAM  pparam;
    PVTEXTEXTINFO   pinfo;

    if (pvd->GaleData.pVtextExtInfo) {
        pinfo = (PVTEXTEXTINFO)((PBYTE)hvdm
                              + (ULONG)(pvd->GaleData.pVtextExtInfo));
        if (pinfo->VideoExtState & VTEXT_EXT_STATE_ACVITE) {
            pparam = (PVTEXTEXTPARAM) ((PBYTE)hvdm
                                     + (pinfo->ExtDrvParamSeg << 4)
                                     +  pinfo->ExtDrvParamOff);
            pmode  = (PVTEXTMODETABLE)((PBYTE)hvdm
                                     + (pinfo->ExtDrvParamSeg << 4)
                                     + pparam->PtrVideoModeTable);
            rows = pmode[pinfo->CurrentModeIndex].ExtModeRows;
        } else {
            rows = 25;
        }
    } else {
        rows = 25;
    }
    return rows;
}

/***LP  vvPtrDrawVtext
 *
 *  This subroutine draws mouse pointer using int 10H.
 *
 *  ENTRY
 *      hvdm  == VDM handle
 *      xNew  == mouse pointer x coordinate
 *      yNew  == mouse pointer y coordinate
 *  EXIT
 *      None
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      Task-time
 *
 *  PSEUDO-CODE                                     REFERENCES
 */

VOID PRIVENTRY vvPtrDrawVtext(HVDM hvdm, ULONG xNew, ULONG yNew)
{
    register PVDMDATA pvd = pVDMData(hvdm);

        /*** The control is in $DISP.SYS ? ***/
    if (*((PBYTE)hvdm + (ULONG)pvd->GaleData.pVtextStub
                      + VTEXT_INT10_STAT_INFLAG) ||                 //J-TS0924
        (pvd->GaleData.flVtext & VDMV_REDRAW_SCREEN)) {             //J-TS0924
        pvd->PtrData.flPtrVideo |= PTR_DRAWN;
        return;
    }

        /*** The control is in V86 routine ? ***/
    if (pvd->GaleData.flVtext & VDMV_PTR_V86_EXECUTING) {
        pvd->PtrData.flPtrVideo |= PTR_DRAWN;
        return;
    }

        /*** Now the control isn't in $DISP.SYS ***/
    if (hvdm == CURRENT_VDM)
        if (pvd->PtrData.flPtrVideo & PTR_DRAWN)
            /*** pointer is already displayed ***/
            vvPtrSetupUpdateVtext(xNew, yNew);
        else
            /*** pointer is not displayed now ***/
            vvPtrSetupDrawVtext(xNew, yNew);
    else {
        if (pvd->PtrData.flPtrVideo & PTR_DRAWN)
            /*** pointer is already displayed ***/
            if ((pvd->PtrData.xCell == xNew) &&
                (pvd->PtrData.yCell == yNew))
                return;
            else
                pvd->GaleData.flVtext |= VDMV_PTR_REQUEST_UPDATE;
        else
            /*** pointer is not displayed now ***/
            pvd->GaleData.flVtext |= VDMV_PTR_REQUEST_DRAW;

        if (!(pvd->GaleData.flVtext & VDMV_PTR_CONTEXT_HOOK))
            VDHArmContextHook(pvd->GaleData.hhookVextPtrContext, hvdm);

        pvd->GaleData.flVtext |= VDMV_PTR_CONTEXT_HOOK;
    }

    pvd->PtrData.flPtrVideo |= PTR_DRAWN;
    pvd->PtrData.xCell       = xNew;
    pvd->PtrData.yCell       = yNew;
}

/***LP  vvPtrEraseVtext
 *
 *  This subroutine erases mouse pointer using int 10H.
 *
 *  ENTRY
 *      hvdm  == VDM handle
 *  EXIT
 *      None
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      Task-time
 *
 *  PSEUDO-CODE                                     REFERENCES
 */

VOID PRIVENTRY vvPtrEraseVtext(HVDM hvdm)
{
    register PVDMDATA pvd = pVDMData(hvdm);

        /*** Now ptr isn't displayed ? ***/
    if (!(pvd->PtrData.flPtrVideo & PTR_DRAWN))
        return;

        /*** reset ptr draw flag ***/
    pvd->PtrData.flPtrVideo &= ~PTR_DRAWN;

        /*** The control is in V86 routine ? ***/
    if (pvd->GaleData.flVtext & VDMV_PTR_V86_EXECUTING) {
        if (hvdm != CURRENT_VDM)
            pvd->GaleData.flVtext |= VDMV_PTR_REQ_ERASE_SP1;
        return;
    }

        /*** The control is in $DISP.SYS ? ***/
    if (*((PBYTE)hvdm + (ULONG)pvd->GaleData.pVtextStub
                      + VTEXT_INT10_STAT_INFLAG)) {
        if (hvdm != CURRENT_VDM)
            pvd->GaleData.flVtext |= VDMV_PTR_REQ_ERASE_SP2;
        return;
    }

    if (hvdm == CURRENT_VDM)
        vvPtrSetupEraseVtext();
    else {
        pvd->GaleData.flVtext |= VDMV_PTR_REQUEST_ERASE;

        if (!(pvd->GaleData.flVtext & VDMV_PTR_CONTEXT_HOOK))
            VDHArmContextHook(pvd->GaleData.hhookVextPtrContext, hvdm);

        pvd->GaleData.flVtext |= VDMV_PTR_CONTEXT_HOOK;
    }
}

/***LP  vvPtrSetupDrawVtext
 *
 *  This subroutine really draws mouse pointer using int 10H.
 *
 *  ENTRY
 *      xNew  == mouse pointer x coordinate
 *      yNew  == mouse pointer y coordinate
 *  EXIT
 *      None
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      Task-time
 *
 *  PSEUDO-CODE                                     REFERENCES
 */

VOID PRIVENTRY vvPtrSetupDrawVtext(ULONG xNew, ULONG yNew)
{
    FPFN addr;

    SEGMENTOF32(addr) = (ULONG)VDMData.GaleData.pVtextStub >> 4;
    OFFSETOF32(addr)  = VTEXT_PTR_DRAW_ENTRY;
    vvPtrSetupDrawUpdateVtext(xNew, yNew, addr);
}

/***LP  vvPtrSetupUpdateVtext
 *
 *  This subroutine really updates mouse pointer using int 10H.
 *
 *  ENTRY
 *      xNew  == mouse pointer x coordinate
 *      yNew  == mouse pointer y coordinate
 *  EXIT
 *      None
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      Task-time
 *
 *  PSEUDO-CODE                                     REFERENCES
 */

VOID PRIVENTRY vvPtrSetupUpdateVtext(ULONG xNew, ULONG yNew)
{
    FPFN addr;

    SEGMENTOF32(addr) = (ULONG)VDMData.GaleData.pVtextStub >> 4;
    OFFSETOF32(addr)  = VTEXT_PTR_UPDATE_ENTRY;
    vvPtrSetupDrawUpdateVtext(xNew, yNew, addr);
}

/***LP  vvPtrSetupDrawUpdateVtext
 *
 *  This subroutine really draw/updates mouse pointer using int 10H.
 *
 *  ENTRY
 *      xNew  == mouse pointer x coordinate
 *      yNew  == mouse pointer y coordinate
 *      pAddr == V86 subroutine addr
 *  EXIT
 *      None
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      Task-time
 *
 *  PSEUDO-CODE                                     REFERENCES
 */

VOID PRIVENTRY vvPtrSetupDrawUpdateVtext(ULONG xNew, ULONG yNew, FPFN pAddr)
{
    /*** Save new pointer location ***/
    VDMData.PtrData.xCell = xNew;
    VDMData.PtrData.yCell = yNew;

    /*** Push all VDM's general-purpose registers ***/
    VDHPushRegs(VDHREG_GENERAL);

    /*** Setup new pointer location parameter ***/
    *StubAccess(PWORD, VTEXT_PTR_PARAM_XNEW)
        = (WORD)(xNew / VDMData.PtrData.vmssVideo.vmss_ulCellWidth);

    *StubAccess(PWORD, VTEXT_PTR_PARAM_YNEW)
        = (WORD)(yNew / VDMData.PtrData.vmssVideo.vmss_ulCellHeight);

    *StubAccess(PWORD, VTEXT_PTR_PARAM_ATTRAND)
        = (WORD)(VDMData.PtrData.ulTextANDMaskVideo);

    *StubAccess(PWORD, VTEXT_PTR_PARAM_ATTRXOR)
        = (WORD)(VDMData.PtrData.ulTextXORMaskVideo);

    /*** Set up return hook for call ***/
    VDHArmReturnHook(VDMData.GaleData.hhookVextPtrReturn, VDHARH_CSEIP_HOOK);

    /*** Prepare for call to V86 pointer drawing subroutine ***/
    VDHPushFarCall(pAddr);

    /*** setup 'executing in V86' flag ***/
    VDMData.GaleData.flVtext |= VDMV_PTR_V86_EXECUTING;
}

/***LP  vvPtrSetupEraseVtext
 *
 *  This subroutine really erases mouse pointer using int 10H.
 *
 *  ENTRY
 *      None
 *  EXIT
 *      None
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      Task-time
 *
 *  PSEUDO-CODE                                     REFERENCES
 */

VOID PRIVENTRY vvPtrSetupEraseVtext()
{
    FPFN addr;

    /*** Push all VDM's general-purpose registers ***/
    VDHPushRegs(VDHREG_GENERAL);

    /*** Set up return hook for call ***/
    VDHArmReturnHook(VDMData.GaleData.hhookVextPtrReturn, VDHARH_CSEIP_HOOK);

    /*** Prepare for call to V86 pointer drawing subroutine ***/
    SEGMENTOF32(addr) = (ULONG)VDMData.GaleData.pVtextStub >> 4;
    OFFSETOF32(addr)  = VTEXT_PTR_ERASE_ENTRY;
    VDHPushFarCall(addr);

    /*** setup 'executing in V86' flag ***/
    VDMData.GaleData.flVtext |= VDMV_PTR_V86_EXECUTING;
}

/***LP  VVVtextUpdatePtrContext()
 *
 *  This subroutine receives the result from pointer draw int 10H.
 *
 *  ENTRY
 *      p - (ignored)
 *      pcrf -> VDM register frame (ignored)
 *  EXIT
 *      None
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      VDM Task-time
 *
 *  PSEUDO-CODE                                     REFERENCES
 */

VOID HOOKENTRY VVVtextUpdatePtrContext(PVOID p, PCRF pcrf)
{
    if      (VDMData.GaleData.flVtext & VDMV_PTR_REQUEST_DRAW)
        vvPtrSetupDrawVtext(VDMData.PtrData.xCell, VDMData.PtrData.yCell);

    else if (VDMData.GaleData.flVtext & VDMV_PTR_REQUEST_UPDATE)
        vvPtrSetupUpdateVtext(VDMData.PtrData.xCell, VDMData.PtrData.yCell);

    else if (VDMData.GaleData.flVtext & VDMV_PTR_REQUEST_ERASE)
        vvPtrSetupEraseVtext();

    VDMData.GaleData.flVtext &= ~(VDMV_PTR_REQUEST_DRAW   |
                                  VDMV_PTR_REQUEST_UPDATE |
                                  VDMV_PTR_REQUEST_ERASE  |
                                  VDMV_PTR_CONTEXT_HOOK);
}

/***LP  VVVtextPtrReturn()
 *
 *  This subroutine receives the result from pointer draw int 10H.
 *
 *  ENTRY
 *      p - (ignored)
 *      pcrf -> VDM register frame (ignored)
 *  EXIT
 *      None
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      VDM Task-time
 *
 *  PSEUDO-CODE                                     REFERENCES
 */

VOID HOOKENTRY VVVtextPtrReturn(PVOID p, PCRF pcrf)
{
    /*** reset 'executing in V86' flag ***/
    VDMData.GaleData.flVtext &= ~VDMV_PTR_V86_EXECUTING;

    /*** restore V86 registers ***/
    VDHPopRegs(VDHREG_GENERAL);

    /*** pointer erase request is called from VVSetBgnd during V86 ***/
    /*** pointer draw routine                                      ***/
    if (VDMData.GaleData.flVtext & VDMV_PTR_REQ_ERASE_SP1) {
        VDMData.GaleData.flVtext &= ~VDMV_PTR_REQ_ERASE_SP1;
        vvPtrSetupEraseVtext();
    }
}
#endif  //VTEXT

#pragma END_SWAP_CODE
