/*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 = VVXVIO.C
 *
 * DESCRIPTIVE NAME = Virtual Video System XVIO support routines
 *
 *
 * VERSION = V2.0
 *
 * DATE      92/07/14
 *
 * DESCRIPTION  This module contains the XVIO support routines.
 *
 *
 * FUNCTIONS    vxSetCursor()           Set cursor
 *              vxGetCursor()           Get cursor
 *              vxCopyLVB()             Copy LVB
 *              vxWriteString()         Write string
 *              vxSaveScreen()          Save graphics mode screen
 *              vxRestoreScreen()       Restore graphics mode screen
 *              vxSetVVDType()          Set VVD type
 *              vxAddEvent()            Add event
 *              vxFlushEvent()          Flush event
 *              vxSetStatus()           Set status
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/

#ifdef  XVIO

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

#define INCL_DOSERRORS
#include <bseerr.h>

#pragma BEGIN_SWAP_DATA

extern HVDD       hvddVXVIO;
extern VXREGISTER XVIOEntry;

#pragma END_SWAP_DATA


#pragma BEGIN_SWAP_CODE


/***LP  vxSetCursor() - XVIO set cursor
 *
 *  This function sets cursor position & attribute.
 *
 *  ENTRY
 *      hvdm      -> VDM
 *      ul1       == input buffer size
 *      pvxCursor -> cursor position & attribute
 *      ul2       == output buffer size (Not used)
 *      pOut      -> output buffer      (Not used)
 *  EXIT
 *      SUCCESS
 *          Zero
 *      FAILURE
 *          Error code (ie, invalid function, etc)
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      Task-time
 *
 *  PSEUDO-CODE                                     REFERENCES
 */

LONG PRIVENTRY vxSetCursor(HVDM hvdm,
                    ULONG ul1, PVXCURSOR pvxCursor, ULONG ul2, PVOID pOut)
{
    register PVDMDATA pvd = pVDMData(hvdm);

    if (ul1 < sizeof(VXCURSOR) || hvdm == INVALID_HVDM)
        return ERROR_INVALID_PARAMETER;

    if ((pvd->ulBIOSMode != 0x03) && (pvd->ulBIOSMode != 0x73))
        return NO_ERROR;

    /*** Don't let mode data change underneath us ***/
    RequestMutexSem(pvd->hmxVideoState);

    /*** Make sure the VDM has a valid state
        (ie, initial INT 10h complete) ***/
    if (!(pvd->flVDMVideo & VDM_STATEINIT)       ||
         (pvd->flVDMVideoJ & VDMJ_GRAPHICSWRITE) ||
         (pvd->flVDMVideo & VDM_MODECHANGING)) {
        ReleaseMutexSem(pvd->hmxVideoState);
        if (pvd->flVDMVideo & VDM_FROZEN)
            return ERROR_ACCESS_DENIED;
        return ERROR_NOT_READY;
    }

    if (pvxCursor->vxc_frequest & VXC_SETPOSITION)
        vvSetCurPosGale(hvdm, pvxCursor->vxc_row,
                              pvxCursor->vxc_col);

    if (pvxCursor->vxc_frequest & VXC_SETCTYPE)
        vvSetCurTypeGale(hvdm, pvxCursor->vxc_ulScanStart,
                               pvxCursor->vxc_ulScanEnd,
                               pvxCursor->vxc_attribute);

    ReleaseMutexSem(pvd->hmxVideoState);

    return NO_ERROR;
}


/***LP  vxGetCursor() - XVIO get cursor
 *
 *  This function gets cursor position & attribute.
 *
 *  ENTRY
 *      hvdm      -> VDM
 *      ul1       == input buffer size  (Not used)
 *      pIn       -> input buffer       (Not used)
 *      ul2       == output buffer size
 *      pvxCursor -> output buffer
 *  EXIT
 *      SUCCESS
 *          Zero
 *      FAILURE
 *          Error code (ie, invalid function, etc)
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      Task-time
 *
 *  PSEUDO-CODE                                     REFERENCES
 */

LONG PRIVENTRY vxGetCursor(HVDM hvdm,
                    ULONG ul1, PVOID pIn, ULONG ul2, PVXCURSOR pvxCursor)
{
    register PVDMDATA pvd = pVDMData(hvdm);

    if (ul2 < sizeof(VXCURSOR) || !pvxCursor || hvdm == INVALID_HVDM)
        return ERROR_INVALID_PARAMETER;

    RequestMutexSem(pvd->hmxVideoState);

    if (!(pvd->flVDMVideo & VDM_STATEINIT)) {
        ReleaseMutexSem(pvd->hmxVideoState);
        return ERROR_NOT_READY;
    }

    vxUpdateCursorData(hvdm);

    *pvxCursor = pvd->XVIOData.vxCursor;

    pvd->XVIOData.vxCursorPrev = pvd->XVIOData.vxCursor;

    ReleaseMutexSem(pvd->hmxVideoState);

    return NO_ERROR;
}


/***LP  vxCopyLVB() - XVIO copy LVB
 *
 *  This function gets LVB copy.
 *
 *  ENTRY
 *      hvdm   -> VDM
 *      ul1    == input buffer size
 *      pvxLVB -> LVB rectangle
 *      ul2    == output buffer size
 *      pLVB   -> LVB
 *  EXIT
 *      SUCCESS
 *          Zero
 *      FAILURE
 *          Error code (ie, invalid function, etc)
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      Task-time
 *
 *  PSEUDO-CODE                                     REFERENCES
 */

LONG PRIVENTRY vxCopyLVB(HVDM hvdm,
                    ULONG ul1, PVXLVB pvxLVB, ULONG ul2, PBYTE pLVB)
{
    LONG rc = NO_ERROR;
    register PVDMDATA pvd = pVDMData(hvdm);

    if ((ul1 < sizeof(VXLVB))  || !pvxLVB ||
        (hvdm == INVALID_HVDM) || !pLVB)
        return ERROR_INVALID_PARAMETER;

    RequestMutexSem(pvd->hmxVideoState);

    rc = vvSysCopyLVBSub(hvdm, ul1, pvxLVB, ul2, pLVB, FALSE);

    if (rc && (pvd->flVDMVideo & VDM_FROZEN))
      rc = ERROR_ACCESS_DENIED;

    ReleaseMutexSem(pvd->hmxVideoState);
    return rc;
}


/***LP  vxWriteString() - XVIO write string
 *
 *  This function writes string.
 *
 *  ENTRY
 *      hvdm      -> VDM
 *      ul1       == input buffer size
 *      pvxString -> string position & length
 *      ul2       == output buffer size
 *      pString   -> string
 *  EXIT
 *      SUCCESS
 *          Zero
 *      FAILURE
 *          Error code (ie, invalid function, etc)
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      Task-time
 *
 *  PSEUDO-CODE                                     REFERENCES
 */

LONG PRIVENTRY vxWriteString(HVDM hvdm,
                    ULONG ul1, PVXWSTR pvxWStr, ULONG ul2, PBYTE pString)
{
    register PVDMDATA pvd = pVDMData(hvdm);

    if (ul1 < sizeof(VXWSTR) || hvdm == INVALID_HVDM)
        return ERROR_INVALID_PARAMETER;

    /*** Don't let mode data change underneath us ***/
    RequestMutexSem(pvd->hmxVideoState);

    /*** Make sure the VDM has a valid state
        (ie, initial INT 10h complete) ***/
    if (!(pvd->flVDMVideo & VDM_STATEINIT)       ||
         (pvd->flVDMVideo & VDM_FROZEN)          ||
         (pvd->flVDMVideoJ & VDMJ_GRAPHICSWRITE) ||
         (pvd->flVDMVideo & VDM_MODECHANGING)) {
        ReleaseMutexSem(pvd->hmxVideoState);
        if (pvd->flVDMVideo & VDM_FROZEN)
            return ERROR_ACCESS_DENIED;
        return ERROR_NOT_READY;
    }

    VDHFreezeVDM(hvdm);

    pvd->XVIOData.vxWStr = *pvxWStr;

    if ((pvd->ulBIOSMode == 0x03) || (pvd->ulBIOSMode == 0x73)) {
        vvExtWriteStrGale(hvdm, &(pvd->XVIOData.vxWStr), pString);
    } else if ((pvd->ulBIOSMode == 0x11) ||
               (pvd->ulBIOSMode == 0x12) ||
               (pvd->ulBIOSMode == 0x72)) {
        memcpy(pvd->XVIOData.GaleXVIOLVB, pString,
                (pvd->ulBIOSMode == 0x72) ? 80 * 25 * 4 :
                                            80 * 30 * 4);
        if (!vdhBTS(&pvd->flVDMVideo, LOG2(VDM_UPDATEHOOK))) {
            pvd->flVDMVideoJ |= VDMJ_GRAPHICSWRITE;
            VDHArmContextHook(pvd->hhookUpdateContext,
                              pvd->hvdmVideo);
        }
    }

    VDHThawVDM(hvdm);

    ReleaseMutexSem(pvd->hmxVideoState);
    return NO_ERROR;
}


/***LP  vxSaveScreen() - XVIO save screen
 *
 *  This function saves graphics full screen image.
 *
 *  ENTRY
 *      hvdm -> VDM
 *      ul1  == input buffer size       (Not used)
 *      pIn  -> input buffer            (Not used)
 *      ul2  == output buffer size      (Not used)
 *      pOut -> output buffer           (Not used)
 *  EXIT
 *      SUCCESS
 *          Zero
 *      FAILURE
 *          Error code (ie, invalid function, etc)
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      Task-time
 *
 *  PSEUDO-CODE                                     REFERENCES
 */

LONG PRIVENTRY vxSaveScreen(HVDM hvdm,
                    ULONG ul1, PVOID pIn, ULONG ul2, PVOID pOut)
{
    register PVDMDATA pvd = pVDMData(hvdm);
    BOOL fSuccess = TRUE;
    INT maxPlanes = pvd->nPlanes;
    INT   iPlane;
    PVOID p;

    if (ul1 < sizeof(RECTL) || hvdm == INVALID_HVDM)
        return ERROR_INVALID_PARAMETER;

    /*** Don't let mode data change underneath us ***/
    RequestMutexSem(pvd->hmxVideoState);

    /*** Make sure the VDM has a valid state
        (ie, initial INT 10h complete) ***/
    if (!(pvd->flVDMVideo & VDM_STATEINIT) ||
         (pvd->flVDMVideo & VDM_MODECHANGING)) {
        ReleaseMutexSem(pvd->hmxVideoState);
        return ERROR_NOT_READY;
    }

    /*** check video mode is graphics ***/
    if ((pvd->ulBIOSMode != 0x11) &&
        (pvd->ulBIOSMode != 0x12) &&
        (pvd->ulBIOSMode != 0x72)) {
        ReleaseMutexSem(pvd->hmxVideoState);
        return NO_ERROR;
    }

    VDHFreezeVDM(hvdm);

    pvd->GaleData.GaleInternalAccess = TRUE;

    vvTransferBuffer(hvdm, 0, FALSE);

    /* Allocating buffers apPlaneXvio[] for XVIO start */

    for (iPlane = PLANE0; iPlane < maxPlanes; iPlane++) {

        if (pvd->anpgPlane[BANK0][iPlane]) {    /* If someting is saved. */
            if (p = VDHAllocPages(NULL, pvd->anpgPlane[BANK0][iPlane],
                                  VDHAP_SYSTEM)) {
                pvd->XVIOData.apPlaneXVIO[iPlane] = p;
                pvd->XVIOData.anpgPlaneXVIO[iPlane]
                                            = pvd->anpgPlane[BANK0][iPlane];
            } else {
                fSuccess = FALSE;
                break;
            }
        } else {                        /* Noting is saved. */
            pvd->XVIOData.apPlaneXVIO[iPlane]   = NULL;
            pvd->XVIOData.anpgPlaneXVIO[iPlane] = 0;
        }
    }  /* end of for */

    /* if successfully allocated, copy from apPlane to apPlaneXvio. */
    if (fSuccess) {
        for (iPlane = PLANE0; iPlane < maxPlanes; iPlane++) {
            if (pvd->apPlane[BANK0][iPlane])    /* Something saved */
                memcpy(pvd->XVIOData.apPlaneXVIO[iPlane],
                       pvd->apPlane[BANK0][iPlane],
                       pvd->anpgPlane[BANK0][iPlane] * PAGESIZE);
        }  /* end of for */
    } else {
        for (iPlane = PLANE0; iPlane < maxPlanes; iPlane++) {
            if (pvd->XVIOData.apPlaneXVIO[iPlane])
                VDHFreePages(pvd->XVIOData.apPlaneXVIO[iPlane]);
            pvd->XVIOData.apPlaneXVIO[iPlane]   = NULL;
            pvd->XVIOData.anpgPlaneXVIO[iPlane] = 0;
        }
    }

    /* Now graphics mode XVIO is active on the screen */
    pvd->flVDMVideoJ |= VDMJ_XVIOGACTIVE;

    pvd->GaleData.GaleInternalAccess = FALSE;

    VDHThawVDM(hvdm);
    ReleaseMutexSem(pvd->hmxVideoState);

    return NO_ERROR;
}


/***LP  vxRestoreScreen() - XVIO restore screen
 *
 *  This function restores graphics full screen image.
 *
 *  ENTRY
 *      hvdm -> VDM
 *      ul1  == input buffer size       (Not used)
 *      pIn  -> input buffer            (Not used)
 *      ul2  == output buffer size      (Not used)
 *      pOut -> output buffer           (Not used)
 *  EXIT
 *      SUCCESS
 *          Zero
 *      FAILURE
 *          Error code (ie, invalid function, etc)
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      Task-time
 *
 *  PSEUDO-CODE                                     REFERENCES
 */

LONG PRIVENTRY vxRestoreScreen(HVDM hvdm,
                    ULONG ul1, PVOID pIn, ULONG ul2, PVOID pOut)
{
    register PVDMDATA pvd = pVDMData(hvdm);
    FLAGS flDirty = -1;
    INT iPlane;
    INT iEvent;

    if (hvdm == INVALID_HVDM)
        return ERROR_INVALID_PARAMETER;

    /* Make sure the VDM has a valid state. */
    /*(ie, initial INT 10h complete)        */
    if (!(pvd->flVDMVideo & VDM_STATEINIT) ||
         (pvd->flVDMVideo & VDM_MODECHANGING)) {
        return ERROR_NOT_READY;
    }

    if ((pvd->ulBIOSMode != 0x11) &&
        (pvd->ulBIOSMode != 0x12) &&
        (pvd->ulBIOSMode != 0x72)) {
        return NO_ERROR;
    }

    /* check APA data is now saved in XVIO buffer */
    if (!(pvd->flVDMVideoJ & VDMJ_XVIOGACTIVE))
        return NO_ERROR;

    /* Don't let mode data change underneath us */
    RequestMutexSem(pvd->hmxVideoState);
    VDHFreezeVDM(hvdm);

    /* restore APA contents */
    if (pvd->flVDMVideo & VDM_WINDOWED) {       /* windowed */
        for (iPlane = PLANE0; iPlane < pvd->nPlanes; iPlane++) {
            if (pvd->apPlane[BANK0][iPlane])
                if (pvd->XVIOData.apPlaneXVIO[iPlane])
                    memcpy(pvd->apPlane[BANK0][iPlane],
                           pvd->XVIOData.apPlaneXVIO[iPlane],
                           pvd->anpgPlane[BANK0][iPlane] * PAGESIZE);
                else
                    memset(pvd->apPlane[BANK0][iPlane], 0,
                           pvd->anpgPlane[BANK0][iPlane] * PAGESIZE);
        }  /* end of for */
    }

    pvd->GaleData.GaleInternalAccess = TRUE;
    vvTransferBuffer(hvdm, 0, TRUE);
    pvd->GaleData.GaleInternalAccess = FALSE;

    if (pvd->flVDMVideo & VDM_WINDOWED) {       /* windowed */
        pvd->flVDMVideoJ |= VDMJ_XVIOGHIDE;
        vvAddEvent(hvdm, VVDEVENT_LVB, SSToDS(&flDirty), 0);

        /* free APA save memory */
        for (iPlane = PLANE0; iPlane < pvd->nPlanes; iPlane++) {
            if (pvd->XVIOData.apPlaneXVIO[iPlane])
                VDHFreePages(pvd->XVIOData.apPlaneXVIO[iPlane]);
            pvd->XVIOData.apPlaneXVIO[iPlane]   = NULL;
            pvd->XVIOData.anpgPlaneXVIO[iPlane] = 0;
        }  /* end of for */
    }

    VDHThawVDM(hvdm);
    ReleaseMutexSem(pvd->hmxVideoState);

    pvd->flVDMVideoJ &= ~VDMJ_XVIOGACTIVE;

        /* String write request from XVIO is queued ? */
    if (pvd->flVDMVideoJ & VDMJ_GRAPHICSWRITE)
        pvd->flVDMVideoJ |= VDMJ_CANCELWRITE;   /* cancel it */

    return NO_ERROR;
}


/***LP  vxSetVVDType() - Inform VVD type of newly created VDM
 *
 *  ENTRY
 *      hvdm   -> VDM
 *      hVVD   == Video VDD handle
 *  EXIT
 *      None
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      Task-time
 *
 *  PSEUDO-CODE                                     REFERENCES
 */

VOID PRIVENTRY vxSetVVDType(HVDM hvdm, ULONG hVVD)
{
    if (hvddVXVIO)
        (*XVIOEntry.vxr_XVIOEntry.vxex_SetVVDType)(hvdm, hVVD);
}


/***LP  vxAddEvent() - Add event to the "event queue"
 *
 *  ENTRY
 *      hvdm   -> VDM
 *      iEvent == event ordinal
 *      pEvent -> event data (varies from one event to another)
 *      flAdd  == Event flags (eg, XEVENT_FLUSH, XEVENT_OWNER)
 *  EXIT
 *      None
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      Task-time
 *
 *  PSEUDO-CODE                                     REFERENCES
 */

VOID PRIVENTRY vxAddEvent(HVDM hvdm, INT iEvent, PVOID pEvent, FLAGS flAdd)
{
    if (hvddVXVIO)
        (*XVIOEntry.vxr_XVIOEntry.vxex_AddEvent)(hvdm, iEvent, pEvent, flAdd);
}


/***LP  vxFlushEvent() - Flush event from the "event queue"
 *
 *  ENTRY
 *      hvdm    -> hvdm
 *      iEvent  == event ordinal
 *      flFlush == Event flags (eg, XEVENT_OWNER)
 *  EXIT
 *      None
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      Task-time
 *
 *  PSEUDO-CODE                                     REFERENCES
 */

VOID PRIVENTRY vxFlushEvent(HVDM hvdm, INT iEvent, FLAGS flFlush)
{
    if (hvddVXVIO)
        (*XVIOEntry.vxr_XVIOEntry.vxex_FlushEvent)(hvdm, iEvent, flFlush);
}

/***LP  vxSetStatus() - Inform VVD internal status change
 *
 *  ENTRY
 *      hvdm     -> VDM
 *      ulStatus == changed status
 *      flSet    == Set/Reset
 *  EXIT
 *      None
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      Task-time
 *
 *  PSEUDO-CODE                                     REFERENCES
 */

VOID PRIVENTRY vxSetStatus(HVDM hvdm, ULONG ulStatus, ULONG flSet)
{
    if (hvddVXVIO)
        (*XVIOEntry.vxr_XVIOEntry.vxex_SetStatus)(hvdm, ulStatus, flSet);
}

#endif  //XVIO


#pragma END_SWAP_CODE
