/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT (C) Microsoft Corporation, 1989                                 */
/* 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 = VMUSER.C
 *
 * DESCRIPTIVE NAME = Virtual Mouse Device Driver User-event Processing
 *
 *
 * VERSION = V2.0
 *
 * DATE      03/20/92
 *
 * DESCRIPTION This module contains the VMD's user-event handlers.
 *
 *
 * FUNCTIONS
 *
 *   VMCreate()      VDM creation notification
 *   VMTerminate     VDM Destruction
 *   VMDOSLink       Provide an interface for DOS Device driver
 *   VMSetFgnd()     VDM foreground notification
 *   VMSetBgnd()     VDM background notification
 *   VMMouseCapture  Set Mouse Capture flag
 *   VMGrabAccess()  VDM Get Exclusive Mouse Access
 *
 *
 * ENTRY POINTS:
 *
 * DEPENDENCIES:
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/
#include "vmdp.h"
#include "vmint33.h"

#ifdef   VDDSTRICT
MODNAME = __FILE__;
#endif

/*
**    External References
*/

extern MHARDWARE mhwInstalled;
extern BOOL fMouseEnabled;

extern HHOOK hhookSendEventHook;      /* hook handle for vmSendEventHook     */
extern HHOOK hhookUserSubReturnHook;/* hook handle for VMUserSubReturnHook   */
extern FPFNPDD fpfnPMRequestProc;
extern USHORT nThreshold;

extern USHORT uxScale;
extern USHORT uyScale;
extern USHORT usMouExclusive;
extern ULONG fsstate;

/*
** protocols inside VMUSER.C
*/

VOID HOOKENTRY VMDOSLink(PVOID p,PCRF pcrf);


#pragma  BEGIN_SWAP_DATA

VPVOID vpBP;                          /* breakpoint address for ARPL         */
SZ szVMBoot =
{
  '#', VDMP_ORD_VMBOOT+'0', 0
} ;
extern PSZ pszPropMouseCapture;
extern LONG ulsgCapture;
extern IOH iohVM;

#pragma  END_SWAP_DATA



#pragma  BEGIN_SWAP_CODE

/****************************************************************************
 *
 *  FUNCTION NAME  :  VMCreate()
 *
 *  DESCRIPTION    :  VDM creation notification
 *
 *  This registered subroutine is called each time a new VDM is created
 *  (see VDHInstallUserHook for complete semantics).
 *
 *  INPUT    :
 *      hvdm -> new VDM
 *  OUTPUT   :
 *      SUCCESS
 *          TRUE (new VDM accepted)
 *      FAILURE
 *          FALSE (could not allocate resources)
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      VDM Task-time
 *
 *  PSEUDO-CODE                                     REFERENCES
 *      define Int IRQ hook                             VDHInstallIntHook()
 *      define Int 33h hook
 *      allocate VDM memory for Int 33h router          VDHAllocDosMem()
 *      patch Int 33h router with hook address
 *      copy router into VDM memory                     VDHCopyMem()
 *      patch Int 33h vector with address of router
 *      inform video VDD the default CRT page
 *
 ****************************************************************************/

BOOL EXPENTRY VMCreate(HVDM hvdm)
{
  BOOL fVMBoot;
  PSZ pszVMBoot = NULL;
  register PBVDM pvdm = NULL;

    /*
    ** The following is for a hypothetical "no mouse" property that
    ** would disable all built-in mouse support for the current VDM -          
    */

#ifdef   NOMOUSEPROP
  if ( * ( PSZ )VDHQueryProperty( szNoMouse ) )
    fMouseEnabled = FALSE;
  return  TRUE;
}

#endif

     AssertTRUE(VDMData.mstates.fPtrHidden == PTR_HIDDEN);
     AssertTRUE(VDMData.mstates.fLPenEmulate);

         /*
         ** Define Int IRQ hook
         */

     VDHInstallIntHook(hvdm,
                       INTFROMIRQ(mhwInstalled.mhw_irq),
                       VMUserSubIntHook,
                       !VDH_ASM_HOOK);

         /*
         ** Define Int 33h hook
         */

     VDHInstallIntHook(hvdm,
                       INT_MOUSE,
                       VMInt33Hook,
                       !VDH_ASM_HOOK);

     VDHInstallIntHook(hvdm,
                       BIOSINT_OSHOOK,
                       vmInt15Hook,
                       !VDH_ASM_HOOK);

         /*
         **  save away ARPL addr for later
         */

     vpBP = VDMBase.rb_avpIVT[INT_MOUSE];

         /*
         **  Install Int Hook for VDD - DOS communication
         */

     /*
     **             VDHInstallIntHook(hvdm,
     **                          0x66,
     **                          VMDOSLink,
     **                          !VDH_ASM_HOOK);
     */

     /*            VDHRegisterAPI(VMOUSE_VDDAPI_ID,(PFNHOOK)VMDOSLink,0); */
     VDHRegisterAPI(VMD_NAME,(PFNHOOK)VMDOSLink,(PFNHOOK)VMDOSLink);

     if ( ( hhookSendEventHook = VDHAllocHook(VDH_CONTEXT_HOOK,
                                           ( PFNARM ) vmSendEvent,
                                           sizeof( HVDM * ) ) ) == NULL )
         return  FALSE;

       *(HVDM *) VDHQueryHookData(hhookSendEventHook) = hvdm;

     if ( ( hhookUserSubReturnHook = VDHAllocHook( VDH_RETURN_HOOK,
                                        ( PFNARM ) VMUserSubReturnHook,
                                                         0 ) ) ==  NULL )
       {
         return  FALSE;
       }

     VDMData.ulSG = VDHQuerySysValue(hvdm,VDHLSV_SESSIONID);

     vmSetCRTPage(hvdm,VDMData.mstates.ulVideoPage);

         /*
         ** For VMs, we must not allocate memory for an INT 33h router
         */

     /*
     ** if (!*(PSZ)VDHQueryProperty(szVMBoot))
     */

     pszVMBoot = (PSZ)VDHQueryProperty(szVMBoot);

     if ( !*pszVMBoot )
         pvdm = VDHAllocDosMem(VMInt33RouterLength);

       /*
       ** Free memory from VDHQueryProperty
       */

     if ( pszVMBoot )
         VDHFreeMem(pszVMBoot);

     if ( VDHQueryProperty ( pszPropMouseCapture ) )
     {
       fsstate |= SESSION_EXCMOUSE;
       ulsgCapture = (LONG)VDMData.ulSG;
     }

     if ( pvdm )
     {

             /*
             ** Patch Int 33h router with hook address
             */

       *(PULONG)((ULONG)vmInt33Router+VMInt33BP) = (ULONG)VDMBase.rb_avpIVT
                                                                 [INT_MOUSE];

             /*
             ** Copy router into the VDM
             */

       VDHCopyMem((PVOID)vmInt33Router, pvdm, VMInt33RouterLength);

             /*
             ** Patch Int 33h vector with address of router entry
             */

       VDMBase.rb_avpIVT[INT_MOUSE] = VPFROMP(pvdm+ROUTER_ENTRYOFFSET);
     }


/*
**             If we have a serial mouse installed then we must
** provide minimal virtualization of that serial port. The physical
** mouse driver zeros out the 40: address at init time. The copy of
** the 40: area that the VDM's get to play with inherits the zero
** from the real 40: area. This should have been sufficient protection
** but some apps (like ProComm Plus) use hardcoded serial port addresses.
*/

/*
** If the MHARDWARE packet returned back from MOUSE.SYS contains the
** upgraded packet size (9), which has the ComPort tagged on AND
** we have a serial mouse attached.
*/

     if ( mhwInstalled.mhw_nb == sizeof( MHARDWARE )
             && mhwInstalled.mhw_uType == VMSE_MSS_DEVICE
             && mhwInstalled.mhw_ComNum
             && mhwInstalled.mhw_ComPort )

         VDHInstallIOHook( hvdm,
                           mhwInstalled.mhw_ComPort, /* Starting port number      */
                           8,                        /* 8 ports (0x_f8 - 0x_ff)   */
                           &iohVM,                   /* I/O Hook information      */
                           !VDH_ASM_HOOK );

     return  TRUE;
}                                      /* VMCreate                           */

/****************************************************************************
 *
 * FUNCTION NAME  : VMTerminate
 *
 * DESCRIPTION    :  VDM Destruction
 *
 *      VDM destruction notification
 *      See VDHInstallUserHook for complete semantics.
 *
 *      This registered subroutine is called each time a VDM
 *      is destroyed.  This handler deallocates the per VDM
 *      resources used by the VDM being destroyed.
 *
 *      INPUT    :
 *          hvdm - handle of VDM
 *
 *      OUTPUT   :
 *          return TRUE
 *
 *      CONTEXT
 *          VDM Task-time
 *
 *      PSEUDOCODE
 *
 ****************************************************************************/

BOOL EXPENTRY VMTerminate(HVDM hvdm)
{
  VMGrabAccess(hvdm, FALSE);          /* Turn X Mouse Mode OFF               */
  return  TRUE;
}                                      /* VMTerminate                        */

/****************************************************************************
 *
 *  FUNCTION NAME  :  VMDOSLink
 *
 *  DESCRIPTION    :  Provide an interface for DOS Device driver
 *
 *      This function is called by our stub
 *      (which is sitting in VDM memory).  The register frame
 *      contains the registers as when invoked by the application.
 *
 *      INPUT    :   p     - reserved
 *              pcrf  - client's register frame.
 *                      Registers contain input parameters
 *                      for services.
 *
 *      OUTPUT   :    Always succeeds;
 *              client's registers contain information, depending
 *                      on which service was called.
 *
 *      GLOBAL EFFECTS
 *          depends on service called
 *
 *      METHOD
 *          use VDHPopInt to remove ROM return address from pcrf
 *          service = client's AH
 *
 ****************************************************************************/

VOID HOOKENTRY VMDOSLink(PVOID p,PCRF pcrf)
{
/*
**              PVOID pVDDName;
*/

  PVOID pBreakPnt;
  VPVOID vpretaddr;

/*
**            pVDDName = PFROMVADDR(DS(pcrf),SI(pcrf));
**            if((*(PULONG)pVDDName)==0x554f4d56) {  Look for letters VMOU
**            VDHPopInt();     prevent return to ROM
*/

  if ( VDHPopStack( 4, SSToDS( &vpretaddr ) ) )
  {
    IP(pcrf) = OFFSETOF16(vpretaddr);
    CS(pcrf) = SEGMENTOF16(vpretaddr);

    switch (AH(pcrf)) {
    case 1:
          pBreakPnt = PFROMVADDR(ES(pcrf), DI(pcrf));
          *(PULONG)pBreakPnt = (ULONG)vpBP;          /* store breakpoint at ES:DI*/
          break;
    case 2:
          VMData.fPassAbs=TRUE;
          CX(pcrf)=64*1024/VMData.vmss.vmss_ulWidth;
          DX(pcrf)=64*1024/VMData.vmss.vmss_ulHeight;
          break;
    }
  }
  return ;
}                                     /* end VMDOSLink                       */

/****************************************************************************
 *
 *  FUNCTION NAME  :  VMSetFgnd()
 *
 *  DESCRIPTION    :  VDM foreground notification
 *
 *  This registered subroutine is called each time a VDM is
 *  switched to foreground (see VDHInstallUserHook for complete semantics).
 *
 *  INPUT    :
 *      hvdm -> new foreground VDM
 *  OUTPUT   :
 *      None
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      Task-time
 *
 *  PSEUDO-CODE                                     REFERENCES
 *      update session state                            fsstate
 *
 ****************************************************************************/

VOID EXPENTRY VMSetFgnd(HVDM hvdm)
{
  register PVDMDATA pvd = pVDMData(hvdm);
  MSSIZE mss;

  REFHVDM(hvdm, ULONG, fsstate) |= SESSION_FGND;
  nThreshold = pvd->mstates.ulThreshold;

  uxScale = vmScaleSensitivity(pvd->mstates.nxMicsPer8Pix,
     pvd->mstates.scaleXMics);
  uyScale = vmScaleSensitivity(pvd->mstates.nyMicsPer8Pix,
     pvd->mstates.scaleYMics);

    /*
    ** Notify the physical mouse driver
    */

  if (pvd->fScrInit)
  {
    vmPMDNotification(hvdm);           /* PenPM EMI change                   */
  }
}                                      /* VMSetFgnd                          */

/****************************************************************************
 *
 *  FUNCTION NAME  :  VMSetBgnd()
 *
 *  DESCRIPTION    :  VDM background notification
 *
 *  This registered subroutine is called each time a VDM is
 *  switched to background (see VDHInstallUserHook for complete semantics).
 *
 *  INPUT    :
 *      hvdm -> new background VDM
 *  OUTPUT   :
 *      None
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      Task-time
 *
 *  PSEUDO-CODE                                     REFERENCES
 *      update session state                            fsstate
 *
 ****************************************************************************/

VOID EXPENTRY VMSetBgnd(HVDM hvdm)
{
  REFHVDM(hvdm, ULONG, fsstate) &= ~SESSION_FGND;
}                                      /* VMSetBgnd                          */

/****************************************************************************
 *
 *  FUNCTION NAME  :  VMMouseCapture
 *
 *  DESCRIPTION    :  Set Mouse Capture flag
 *
 *      This routine is called when the user alters an existing
 *  VDM's Mouse Capture "advanced property" setting.
 *
 *      INPUT    :
 *          op - operation to perform (set)
 *          hvdm - target VDM
 *          cb - length of value
 *          psz - ptr to BOOL value
 *
 *      OUTPUT   :
 *          returns 0 (no error)
 *
 *      Return screen group ID that will capture mouse inputs:
 *    + (Positive ID) --> Mouse Capture for screen group ON
 *    - (Negative ID) --> Mouse Capture for screen group OFF
 *
 *      CONTEXT
 *          OS/2 task context (usually the Shield layer)
 *
 ****************************************************************************/

ULONG EXPENTRY VMMouseCapture(ULONG op,HVDM hvdm,ULONG cb,PSZ psz)
{
  register PVDMDATA pvd = pVDMData(hvdm);
  AssertTRUE(op == VDHPROP_SET);

  if ((BOOL)psz && !(REFHVDM(hvdm, ULONG, fsstate)&SESSION_SEAMLESS))
  {
    REFHVDM(hvdm, ULONG, fsstate) |= SESSION_EXCMOUSE;
    ulsgCapture = (LONG)pvd->ulSG;
  }
  else
  {
    REFHVDM(hvdm, ULONG, fsstate) &= ~SESSION_EXCMOUSE;
    ulsgCapture = (LONG)(-pvd->ulSG);
  }
  return 0;
}

/****************************************************************************
 *
 *  FUNCTION NAME  :  VMGrabAccess()
 *
 *  DESCRIPTION    :  VDM Get Exclusive Mouse Access
 *
 *  This registered subroutine is called each time a VDM is
 *  needs to get exclusive access to the physical mouse driver.
 *
 *  INPUT    :
 *         hvdm
 *         fMouExcAcc - TRUE  - Turn X Mouse Mode ON
 *                      FALSE - Turn X Mouse Mode OFF
 *  OUTPUT   :
 *      None
 *  USES
 *      32-bit small-model PASCAL calling/register conventions
 *
 *  CONTEXT
 *      Task-time
 *
 *  PSEUDO-CODE                                     REFERENCES
 *
 ****************************************************************************/

VOID EXPENTRY VMGrabAccess(HVDM hvdm,BOOL fMouExcAcc)
{
  register PVDMDATA pvd = pVDMData(hvdm);
  MOUGRAB MouGrab;

    /*
    ** Notify the physical mouse driver
    */

  if (pvd->fScrInit)
  {
    if (fMouExcAcc && !(REFHVDM(hvdm, ULONG, fsstate)&SESSION_SEAMLESS))
      usMouExclusive = pvd->ulSG;
    else
      usMouExclusive = 0;

    MouGrab.uscMouGrab = sizeof(MouGrab);
    MouGrab.usSG = pvd->ulSG;
    MouGrab.fMouGrab = fMouExcAcc;
    AssertRC((*fpfnPMRequestProc)(PMDCMD_GRABACCESS, F16PFROMSSP(&MouGrab),
                                                                     NULL));
  }
}                                      /* VMGrabAccess                       */
#pragma  END_SWAP_CODE
