/*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 = TDIMOVE.C
 *
 * DESCRIPTIVE NAME = Touch dd, moveable code seg
 *
 *
 * VERSION = V2.0
 *
 * DATE        07/30/91
 *
 * DESCRIPTION
 *
 *
 * FUNCTIONS      NewStratEntry,     ReqOpen,           ReqClose,
 *                ReqIoctl,          ReqInputFlush,     ReqDeinstall,
 *                ReqShutdown,       ReqError,          MonitorReg,
 *                IocSetCoordSys,    IocGetCoordSys,    IocSetSelMech,
 *                IocGetSelMech,     IocSetEventMask,   IocGetEventMask,
 *                IocSetQueueSize,   IocGetQueueSize,   IocSetEmulState,
 *                IocGetEmulState,   IocReadEventQueue, SetEmulState,
 *                SgControl,         SgCreate,          MonitorHandler,
 *                Ring0Init,         AccessCheck,       CheckPkt,
 *                QueueRead,         FlushMonitorChain, Idc_EnableDevice,
 *                Idc_DisableDevice, Idc_QueryConfig,   Idc_ReadEnable,
 *                Idc_SetEmulation,  Idc_SetBeep,       InitVdmCb,
 *                InitFsCb,          SetCBDefaults,     FindCb,
 *                FindCbPtr,         AllocCb,           FreeSgcb,
 *                AllocMem,          NewPddEntry,       PddRegisterVdd,
 *                PddQueryConfig,    PddSetEmul,        PddDisable,
 *                PddSetExclAcc,     panic.
 *
 * ENTRY POINTS:
 *
 * DEPENDENCIES:
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/

/*
** Includes
*/
#define  INCL_DOSINFOSEG
#define  INCL_DOSSESMGR
#include <os2.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "toudefs.h"
#include "reqblk.h"
#include "toutypes.h"
#include "devhlp.h"
#include "touasm.h"
#include "tdicalls.h"

/*
** Defines
*/
#define  TRUE           (1>0)
#define  FALSE          (!TRUE)

/*
** Typedefs
**   Prototypes
*/
VOID FAR PASCAL NewStratEntry(PREQBLK);

STATIC VOID NEAR PASCAL Ring0Init(VOID);
STATIC VOID NEAR PASCAL SAVEREGS Idc_EnableDevice(VOID);
STATIC VOID NEAR PASCAL SAVEREGS Idc_DisableDevice(VOID);
STATIC USHORT NEAR PASCAL SAVEREGS Idc_QueryConfig(PCONFDAT);
STATIC USHORT NEAR PASCAL SAVEREGS Idc_ReadEnable(PINTPKT);
STATIC USHORT NEAR PASCAL SAVEREGS Idc_SetEmulation(USHORT);
STATIC USHORT NEAR PASCAL SAVEREGS Idc_SetBeep(USHORT);
STATIC REQFUNC ReqError(PREQBLK);
STATIC REQFUNC ReqInputFlush(PREQBLK);
STATIC REQFUNC ReqOpen(PREQBLK);
STATIC REQFUNC ReqClose(PREQBLK);
STATIC REQFUNC ReqIoctl(PREQBLK);
STATIC REQFUNC ReqDeinstall(PREQBLK);
STATIC REQFUNC ReqShutdown(PREQBLK);
STATIC VOID NEAR PASCAL SetEmulState(USHORT);
STATIC IOCFUNC SgControl(PREQBLK);
STATIC USHORT NEAR PASCAL SgCreate(USHORT,USHORT,USHORT);
STATIC VOID NEAR PASCAL InitVdmCb(USHORT,USHORT,PSGCB);
STATIC VOID NEAR PASCAL SetCBDefaults(PSGCB);
STATIC PSGCB NEAR PASCAL FindCb(USHORT sess);
STATIC PCBTAB NEAR PASCAL FindCbPtr(USHORT,USHORT,PUSHORT);
STATIC PSGCB NEAR PASCAL AllocCb(USHORT,USHORT,USHORT);
STATIC USHORT NEAR PASCAL FreeSgcb(USHORT);
STATIC PMEM NEAR PASCAL AllocMem(USHORT);
STATIC USHORT NEAR PASCAL AccessCheck(PREQBLK,USHORT);
STATIC USHORT NEAR PASCAL CheckPkt(PVOID,USHORT,USHORT);
STATIC IOCFUNC MonitorReg(PREQBLK);
STATIC VOID FAR CDECL SAVEREGS LOADDS MonitorHandler(USHORT);
STATIC USHORT NEAR PASCAL FlushMonitorChain(VOID);
STATIC VOID NEAR PASCAL QueueRead(PEVENT,PSGCB,USHORT);
STATIC VDMFUNC PddRegisterVdd(PUSHORT,PUSHORT);
STATIC VDMFUNC PddQueryConfig(PUSHORT);
STATIC VDMFUNC PddSetEmul(PUSHORT);
STATIC VDMFUNC PddDisable(VOID);
STATIC VDMFUNC PddSetExclAcc(PUSHORT);
/* extern VOID FAR ReqInit( PREQBLK); */
IOCFUNC IocSetCoordSys(PREQBLK);
IOCFUNC IocGetCoordSys(PREQBLK);
IOCFUNC IocSetSelMech(PREQBLK);
IOCFUNC IocGetSelMech(PREQBLK);
IOCFUNC IocSetEventMask(PREQBLK);
IOCFUNC IocGetEventMask(PREQBLK);
IOCFUNC IocSetQueueSize(PREQBLK);
IOCFUNC IocGetQueueSize(PREQBLK);
IOCFUNC IocSetEmulState(PREQBLK);
IOCFUNC IocGetEmulState(PREQBLK);
IOCFUNC IocReadEventQueue(PREQBLK);
VOID FAR PASCAL InitFsCb(PSGCB,NPEVENT);
VOID FAR flush(PSGCB);
VOID FAR CDECL panic(PSZ file,USHORT line,PSZ fmt,...);

/*
** External global data
**
** Data declared near as inherit DS from strategy entry & module is compiled
**      with /A?w switch
*/
extern USHORT NEAR CurrCmd;
extern ULONG NEAR CmdSem;
extern USHORT NEAR CurrSess;
extern USHORT NEAR CallPid;
extern USHORT NEAR SemPid;
extern CONFDAT NEAR DevData;
extern USHORT NEAR NumButtons;
extern USHORT NEAR EMaskMax;
extern UCHAR NEAR fDeInstall;
extern UCHAR NEAR DefaultEmul;
extern USHORT NEAR InitStage;
extern INTPKT NEAR IntPkt;
extern IDC NEAR DD_Idc;
extern FWORD TouVddEntry;
extern USHORT NEAR fVdmEnabled;
extern PSGCB NEAR pFgndSgcb;
extern USHORT NEAR FgndSess;
extern ICB NEAR ICB_In;
extern USHORT NEAR MaxEQLen;
extern UCHAR NEAR NumSess;
extern CBTAB NEAR FsCbTable[];
extern CBTAB NEAR OtherCbTable[];
extern PSGCB NEAR pCurrSgcb;
extern UCHAR NEAR fExclAccess;
extern SGCB NEAR ShellSgcb;
extern TDISELMETHOD NEAR DefSelm;
extern USHORT NEAR DefQSize;

/*
** Local global data
*/
STATIC USHORT NEAR StratNestLvl = 0;
STATIC UCHAR NEAR fDetached = 0;

/*
** VDM access table
*/
STATIC VDMTAB NEAR VdmTable[] =
{
  /* data size from vtouch, Sgcb needed                                      */
  0, 0,                               /* 0 - register                        */
  0, 0,                               /* 1 - q config                        */
  3, 0,                               /* 2 - set emul                        */
  0, 0,                               /* 3 - disable                         */
  0, 0,                               /* 4 - exclusive access                */
} ;

#define  VDMTABMIN      0
#define  VDMTABMAX      (sizeof(VdmTable)/sizeof(VDMTAB)-1)

/*
** Request table
*/
STATIC REQTAB NEAR ReqTable[] =
{
  ReqError,                           /* 00                                  */
  ReqError,                           /* 01                                  */
  ReqError,                           /* 02                                  */
  ReqError,                           /* 03                                  */
  ReqError,                           /* 04                                  */
  ReqError,                           /* 05                                  */
  ReqError,                           /* 06                                  */
  ReqInputFlush,                      /* 07                                  */
  ReqError,                           /* 08                                  */
  ReqError,                           /* 09                                  */
  ReqError,                           /* 0a                                  */
  ReqError,                           /* 0b                                  */
  ReqError,                           /* 0c                                  */
  ReqOpen,                            /* 0d                                  */
  ReqClose,                           /* 0e                                  */
  ReqError,                           /* 0f                                  */
  ReqIoctl,                           /* 10                                  */
  ReqError,                           /* 11                                  */
  ReqError,                           /* 12                                  */
  ReqError,                           /* 13                                  */
  ReqDeinstall,                       /* 14                                  */
  ReqError,                           /* 15                                  */
  ReqError,                           /* 16                                  */
  ReqError,                           /* 17                                  */
  ReqError,                           /* 18                                  */
  ReqError,                           /* 19                                  */
  ReqError,                           /* 1a                                  */
  ReqError,                           /* 1b                                  */
  ReqShutdown                         /* 1c                                  */
} ;

#define  REQTABMIN      0
#define  REQTABMAX      (sizeof(ReqTable)/sizeof(REQTAB)-1)


/*
** Access check:
**         Func,                   Parameter pkt,  Data pkt
*/
STATIC IOCTAB NEAR IocTable[] =
{
  IocSetCoordSys,       ACC_RCHK+ACC_LVL2,   ACC_NONE,            /* 50      */
  ReqError,             ACC_NONE,            ACC_NONE,            /* 51      */
  IocSetSelMech,        ACC_RCHK+ACC_LVL2,   ACC_NONE,            /* 52      */
  IocSetEventMask,      ACC_RCHK+ACC_LVL2,   ACC_NONE,            /* 53      */
  IocSetQueueSize,      ACC_RCHK+ACC_LVL2,   ACC_NONE,            /* 54      */
  IocSetEmulState,      ACC_RCHK+ACC_LVL2,   ACC_NONE,            /* 55      */
  ReqError,             ACC_NONE,            ACC_NONE,            /* 56      */
  ReqError,             ACC_NONE,            ACC_NONE,            /* 57      */
  ReqError,             ACC_NONE,            ACC_NONE,            /* 58      */
  ReqError,             ACC_NONE,            ACC_NONE,            /* 59      */
  ReqError,             ACC_NONE,            ACC_NONE,            /* 5a      */
  ReqError,             ACC_NONE,            ACC_NONE,            /* 5b      */
  ReqError,             ACC_NONE,            ACC_NONE,            /* 5c      */
  ReqError,             ACC_NONE,            ACC_NONE,            /* 5d      */
  ReqError,             ACC_NONE,            ACC_NONE,            /* 5e      */
  ReqError,             ACC_NONE,            ACC_NONE,            /* 5f      */
  IocGetCoordSys,       ACC_NONE,            ACC_WCHK+ACC_LVL2,   /* 60      */
  ReqError,             ACC_NONE,            ACC_NONE,            /* 56      */
  IocGetSelMech,        ACC_NONE,            ACC_WCHK+ACC_LVL2,   /* 62      */
  IocGetEventMask,      ACC_NONE,            ACC_WCHK+ACC_LVL2,   /* 63      */
  IocGetQueueSize,      ACC_NONE,            ACC_WCHK+ACC_LVL2,   /* 64      */
  IocGetEmulState,      ACC_NONE,            ACC_WCHK+ACC_LVL2,   /* 65      */
  IocReadEventQueue,    ACC_RCHK+ACC_LVL2,   ACC_WCHK+ACC_LVL2    /* 66      */
} ;

#define  IOCTABMIN      0x50
#define  IOCTABMAX      (sizeof(IocTable)/sizeof(IOCTAB)-1+IOCTABMIN)


/****************************************************************************
 *
 * FUNCTION NAME = NewStratEntry
 *
 * DESCRIPTION   =
 *   Called from : StratEntry (seg2)
 *
 *
 * INPUT         = (PREQBLK pReqBlk) - Pointer to Request block
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = Request block status
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

extern VOID FAR PASCAL NewStratEntry(PREQBLK pReqBlk)
{
  USHORT typeProc;
  PLINFOSEG pLis;

  ++StratNestLvl;
  CurrCmd = pReqBlk->cmd;

  if (InitStage == 1)
  {
    Ring0Init();
  }

  if (CurrCmd != REQF_CLOSE && DHSemRequest(&CmdSem, -1l))
  {                                   /* sem request failed                  */
    pReqBlk->status = REQE_GENF;
  }
  else
  {                                   /* sem request ok                      */
    pLis = *(PLINFOSEG FAR *)DHGetDOSVar(GDV_LocalInfoSeg);

    if (pLis != NULL)
    {                                 /* get lis, ok                         */
      CurrSess = pLis->sgCurrent;
      CallPid  = pLis->pidCurrent;
      typeProc = pLis->typeProcess;

      if (typeProc == PT_DETACHED)
      {
        CurrSess = SESN_POPUP;
        fDetached = 1;
      }
      else
      {                               /* not detached                        */
        fDetached = 0;
        if (typeProc == PT_WINDOWABLEVIO || typeProc == PT_PM)
        {
          typeProc = PT_FULLSCREEN;
          CurrSess = SESN_SHELL;
        }
      }

      if (CurrCmd != REQF_CLOSE)
      {
        SemPid = CallPid;
      }

      if (typeProc != PT_FULLSCREEN && typeProc != PT_DETACHED)
      {                               /* illegal proc type                   */
        pReqBlk->status = REQE_UCMD;
      }
      else
        if (CurrCmd > REQTABMAX)
        {                             /* illegal cmd                         */
          pReqBlk->status = REQE_UCMD;
        }
        else
          if (InitStage == -1 && CurrCmd != REQF_OPEN && CurrCmd != REQF_CLOSE)
          {                           /* ???                                 */
            pReqBlk->status = REQE_NOTRDY;
          }
          else
            if (CurrCmd == REQF_IOCTL && pReqBlk->ioctl.category == IOC_CAT_GEN
               && pReqBlk->ioctl.function == 0x41)
            {                         /* ioctl, session notification         */

              /* (do not need to do a find cb as does one if needed)         */
              SgControl(pReqBlk);
            }
            else
            {                         /* cmd ok                              */
              if ((pCurrSgcb = FindCb(CurrSess)) != NULL)
                (*ReqTable[CurrCmd].Func)(pReqBlk);
              else
              {                       /* sgcb not found                      */
              #ifdef   DEBUG
                _asm int 3
              #endif
                pReqBlk->status = REQE_GENF;
              }
            }
    }
    else
    {                                 /* get lis failed                      */
      pReqBlk->status = REQE_GENF;
    }

    if (CurrCmd != REQF_CLOSE)
    {
      DHSemClear(&CmdSem);
    }
  }                                   /* if - sem request failed             */

  DHDevDone(pReqBlk);
  --StratNestLvl;
}                                     /* NewStratEntry                       */


/****************************************************************************
 *
 * FUNCTION NAME = ReqOpen
 *
 * DESCRIPTION   =
 *   Called from : NewStratEntry (seg3)
 *
 *
 * INPUT         = (PREQBLK pReqBlk) - Pointer to Request block
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = Request block status
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

STATIC REQFUNC ReqOpen(PREQBLK pReqBlk)
{
  Idc_DisableDevice();

  if (pCurrSgcb->Hdle_Count == 0)
  {                                   /* First open in this screen group     */
    if (CurrSess != SESN_SHELL && CurrSess != SESN_INIT &&
        CurrSess != SESN_POPUP)
    {                                 /* not shell or init or popup session  */
      /* Turn emulation off */
      SetEmulState(pCurrSgcb->EmulState = 0);
    }

    /* allow all data when firdt opened */
    pCurrSgcb->EventMask = TDI_MASK_ALL_DATA;
    pCurrSgcb->DevStatus.blocked = 0;

    if (FlushMonitorChain())
      pReqBlk->status = REQE_GENF;

    /* ??? any need to set pCurrSgcb->QueueSize                              */
    SetCBDefaults(pCurrSgcb);
  }

  ++pCurrSgcb->Hdle_Count;
  Idc_EnableDevice();
}                                     /* ReqOpen                             */


/****************************************************************************
 *
 * FUNCTION NAME = ReqClose
 *
 * DESCRIPTION   =
 *   Called from : NewStratEntry (seg3)
 *
 *
 * INPUT         = (PREQBLK pReqBlk) - Pointer to Request block
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = Request block status
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

STATIC REQFUNC ReqClose(PREQBLK pReqBlk)
{
  USHORT sess;
  PSGCB  pSgcb;

  --pCurrSgcb->Hdle_Count;

  if (pCurrSgcb->Hdle_Count == 0)
  {                                   /* last close                          */
    Idc_DisableDevice();

    /* if( FlushMonitorChain()) */
    /*   pReqBlk->status = REQE_GENF; */
    if (CurrSess != SESN_SHELL && CurrSess != SESN_INIT &&
        CurrSess != SESN_POPUP)
    {                                 /* not shell or init or popup session  */

      /* Reset emulation back to default */
      SetEmulState(pCurrSgcb->EmulState = DefaultEmul);
    }
    Idc_EnableDevice();
  }

}                                     /* ReqClose                            */


/****************************************************************************
 *
 * FUNCTION NAME = ReqIoctl
 *
 * DESCRIPTION   =
 *   Called from : NewStratEntry (seg3)
 *
 *
 * INPUT         = (PREQBLK pReqBlk) - Pointer to Request block
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = Request block status
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

STATIC REQFUNC ReqIoctl(PREQBLK pReqBlk)
{
  USHORT CurrReq;

  CurrReq = pReqBlk->ioctl.function;

  if (pReqBlk->ioctl.category == IOC_CAT_TOU && CurrReq >= IOCTABMIN &&
      CurrReq <= IOCTABMAX && !fDetached)
  {                                   /* valid touch request                 */
    if (AccessCheck(pReqBlk, CurrReq-IOCTABMIN))
      pReqBlk->status = REQE_PARM;
    else
      (*IocTable[CurrReq-IOCTABMIN].Func)(pReqBlk);
  }
  else
    if (pReqBlk->ioctl.category == IOC_CAT_MON && CurrReq == 0x40)
    {                                 /* register a monitor                  */
      MonitorReg(pReqBlk);
    }
    else
      if (pReqBlk->ioctl.category == IOC_CAT_GEN && CurrReq == 0x60 &&
          !fDetached)
      {                               /* query monitor support               */
        ;                             /* no action, monitors are supported   */
      }
      else
      {                               /* request unsupported                 */
        pReqBlk->status = REQE_UCMD;
      }
}                                     /* ReqIoctl                            */


/****************************************************************************
 *
 * FUNCTION NAME = ReqInputFlush
 *
 * DESCRIPTION   =
 *   Called from : NewStratEntry (seg3)
 *
 *
 * INPUT         = (PREQBLK pReqBlk) - Pointer to request block
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = Request block status
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

STATIC REQFUNC ReqInputFlush(PREQBLK pReqBlk)
{
  if (!fDetached)
  {
    cli();

    if (!pCurrSgcb->DevStatus.eq_busy)
    {
      if (FlushMonitorChain())
      {                               /* flush failed                        */
        pCurrSgcb->DevStatus.flush = 0;
        pReqBlk->status = REQE_GENF;
      }
      pCurrSgcb->DevStatus.eq_busy = 0;
    }
    else
      pReqBlk->status = REQE_GENF;

    sti();
  }
  else
  {                                   /* detached                            */
    pReqBlk->status = REQE_UCMD;
  }
}                                     /* ReqInputFlush                       */


/****************************************************************************
 *
 * FUNCTION NAME = ReqDeinstall
 *
 * DESCRIPTION   =
 *   Called from : NewStratEntry (seg3)
 *
 *
 * INPUT         = (PREQBLK pReqBlk) - Pointer to Request block
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = Request block status
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

STATIC REQFUNC ReqDeinstall(PREQBLK pReqBlk)
{
  fDeInstall = TRUE;
}                                     /* ReqDeinstall                        */


/****************************************************************************
 *
 * FUNCTION NAME = ReqShutdown
 *
 * DESCRIPTION   =
 *   Called from : NewStratEntry (seg3)
 *
 *
 * INPUT         = (PREQBLK pReqBlk) - Pointer to Request block
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = Request block status
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

STATIC REQFUNC ReqShutdown(PREQBLK pReqBlk)
{
  Idc_DisableDevice();

#ifdef   DEBUG
  /* DHBeep( DH_BP_TIMED, 100, 500); */
#endif
}                                     /* ReqShutdown                         */


/****************************************************************************
 *
 * FUNCTION NAME = ReqError
 *
 * DESCRIPTION   =
 *   Called from : NewStratEntry (seg3)
 *                 ReqIoctl (seg3)
 *
 *
 * INPUT         = (PREQBLK pReqBlk) - Pointer to request block
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = Request block status
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

STATIC REQFUNC ReqError(PREQBLK pReqBlk)
{
  pReqBlk->status = REQE_UCMD;
}                                     /* ReqError                            */


/****************************************************************************
 *
 * FUNCTION NAME = MonitorReg
 *
 * DESCRIPTION   = Register a monitor
 *   Called from : ReqIoctl (seg3)
 *
 *
 * INPUT         = (PREQBLK pReqBlk)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE - via reqblk
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

STATIC IOCFUNC MonitorReg(PREQBLK pReqBlk)
{
  SHORT REG Index;
  PSGCB pSgcb;

  cli();

  Index = ((PMONREG)(pReqBlk->ioctl.pData))->Index;

  if (fDetached && Index == -1)
    Index = NumSess;

  if (Index < -1 || Index >= (SHORT)NumSess)
  {
    pReqBlk->status = REQE_PARM;
    goto MonitorReg_exit;
  }

  if (Index != -1 && Index != (SHORT)FgndSess)
  {
    if ((pSgcb = FindCb(Index)) == NULL)
    {                                 /* not found, so allocate one          */
      pSgcb = AllocCb(sizeof(SGCB) + MaxEQLen * sizeof(EVENT), Index, 1);
      if (pSgcb == NULL)
      {
        pReqBlk->status = REQE_GENF;
        goto MonitorReg_exit;
      }

      /*
      ** The event q is allocated at the end of CB
      ** & stored near as it is in same segment as pSgcb
      ** because they are allocated as a whole.
      */
      InitFsCb(pSgcb, (NPEVENT)(OFFSETOF(pSgcb) + sizeof(SGCB)));
    }                                 /* if - find cb                        */
  }

  if (pSgcb->Chain_Size == 0)
  {                                   /* no chains yet, so create a monitor  */
    if (DHMonitorCreate(&pSgcb->MonBuf, (PFVOID)MonitorHandler,
                        &pSgcb->Chain_Hdle))
    {
      pReqBlk->status = REQE_GENF;
      goto MonitorReg_exit;
    }
  }

  /* register new monitor buffers */
  if (DHRegister(((PMONREG)(pReqBlk->ioctl.pData))->pIBuff,
                 ((PMONREG)(pReqBlk->ioctl.pData))->pOBuff,
                 SemPid,
                 pSgcb->Chain_Hdle,
                 (UCHAR)((PMONREG)(pReqBlk->ioctl.pData))->fPlace))
  {
    pReqBlk->status = REQE_GENF;
    goto MonitorReg_exit;
  }

  ++pSgcb->Chain_Size;

MonitorReg_exit:
  sti();
}                                     /* MonitorReg                          */


/****************************************************************************
 *
 * FUNCTION NAME = IocSetCoordSys
 *
 * DESCRIPTION   =
 *   Called from : ReqIoctl (seg3)
 *
 *
 * INPUT         = (PREQBLK pReqBlk)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

IOCFUNC IocSetCoordSys(PREQBLK pReqBlk)
{
  PTDICOORDSYS pCSys;

  pCSys = (PTDICOORDSYS)pReqBlk->ioctl.pParms;

  if (pCSys->XMin == pCSys->XMax ||
      pCSys->YMin == pCSys->YMax ||
      pCSys->ZMin == pCSys->ZMax)
  {                                   /* parms error                         */
    pReqBlk->status = REQE_PARM;
  }
  else
  {                                   /* copy parameters                     */
    /* ??? Disable */
    pCurrSgcb->CoordSys = *pCSys;
    flush(pCurrSgcb);                 /* to try to get changes immendiately  */
    /* ??? Enable */
  }
}                                     /* IocSetCoordSys                      */


/****************************************************************************
 *
 * FUNCTION NAME = IocGetCoordSys
 *
 * DESCRIPTION   =
 *   Called from : ReqIoctl (seg3)
 *
 *
 * INPUT         = (PREQBLK pReqBlk)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

IOCFUNC IocGetCoordSys(PREQBLK pReqBlk)
{
  /* copy to data */
  *((PTDICOORDSYS)pReqBlk->ioctl.pData) = pCurrSgcb->CoordSys;
}                                     /* IocGetCoordSys                      */


/****************************************************************************
 *
 * FUNCTION NAME = IocSetSelMech
 *
 * DESCRIPTION   =
 *   Called from : ReqIoctl (seg3)
 *
 *
 * INPUT         = (PREQBLK pReqBlk)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

IOCFUNC IocSetSelMech(PREQBLK pReqBlk)
{
  PTDISELMETHOD pSelm;

  pSelm = (PTDISELMETHOD)pReqBlk->ioctl.pParms;

  if ( pSelm->Type > TDI_SEL_MMAX ||
      (pSelm->Type > 1 && pSelm->NumPoints > TDI_SEL_PMAX) ||
      (pSelm->Type > 1 && pSelm->Tolerance > TDI_SEL_TMAX) ||
      (pSelm->Type > 3 && pSelm->SearchLimit > TDI_SEL_SMAX))
  {                                   /* parms error                         */
    pReqBlk->status = REQE_PARM;
  }
  else
  {                                   /* copy parameters                     */
    /* Disable */
    pCurrSgcb->SelMech = *pSelm;
    /* Enable */
  }
}                                     /* IocSetSelMech                       */


/****************************************************************************
 *
 * FUNCTION NAME = IocGetSelMech
 *
 * DESCRIPTION   =
 *   Called from : ReqIoctl (seg3)
 *
 *
 * INPUT         = (PREQBLK pReqBlk)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

IOCFUNC IocGetSelMech(PREQBLK pReqBlk)
{
  /* copy to data */
  *((PTDISELMETHOD)pReqBlk->ioctl.pData) = pCurrSgcb->SelMech;
}                                     /* IocGetSelMech                       */


/****************************************************************************
 *
 * FUNCTION NAME = IocSetEventMask
 *
 * DESCRIPTION   =
 *   Called from : ReqIoctl (seg3)
 *
 *
 * INPUT         = (PREQBLK pReqBlk)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

IOCFUNC IocSetEventMask(PREQBLK pReqBlk)
{
  USHORT mask;

  mask = *((PUSHORT)pReqBlk->ioctl.pParms);

  if (mask & ~TDI_MASK_BITS)
  {                                   /* parms error                         */
    pReqBlk->status = REQE_PARM;
  }
  else
  {                                   /* copy parameter                      */
    /* Disable */
    pCurrSgcb->EventMask = mask;
    /* Enable */
  }
}                                     /* IocSetEventMask                     */


/****************************************************************************
 *
 * FUNCTION NAME = IocGetEventMask
 *
 * DESCRIPTION   =
 *   Called from : ReqIoctl (seg3)
 *
 *
 * INPUT         = (PREQBLK pReqBlk)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

IOCFUNC IocGetEventMask(PREQBLK pReqBlk)
{
  /* copy to data */
  *((PUSHORT)pReqBlk->ioctl.pData) = pCurrSgcb->EventMask;
}                                     /* IocGetEventMask                     */


/****************************************************************************
 *
 * FUNCTION NAME = IocSetQueueSize
 *
 * DESCRIPTION   =
 *   Called from : ReqIoctl (seg3)
 *
 *
 * INPUT         = (PREQBLK pReqBlk)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

IOCFUNC IocSetQueueSize(PREQBLK pReqBlk)
{
  USHORT size;

  size = *((PUSHORT)pReqBlk->ioctl.pParms);

  if (size > MaxEQLen)
  {                                   /* parms error                         */
    pReqBlk->status = REQE_PARM;
  }
  else
  {                                   /* copy parameters                     */
    /* ??? disable */
    if (size != 0)
      pCurrSgcb->QueueSize = size;
    else
      pCurrSgcb->QueueSize = 10;      /* default                             */
    flush(pCurrSgcb);
    /* ??? enable */
  }
}                                     /* IocSetQueueSize                     */


/****************************************************************************
 *
 * FUNCTION NAME = IocGetQueueSize
 *
 * DESCRIPTION   =
 *   Called from : ReqIoctl (seg3)
 *
 *
 * INPUT         = (PREQBLK pReqBlk)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

IOCFUNC IocGetQueueSize(PREQBLK pReqBlk)
{
  /* copy to data */
  *((PUSHORT)pReqBlk->ioctl.pData) = pCurrSgcb->QueueSize;
}                                     /* IocGetQueueSize                     */


/****************************************************************************
 *
 * FUNCTION NAME = IocSetEmulState
 *
 * DESCRIPTION   =
 *   Called from : ReqIoctl (seg3)
 *
 *
 * INPUT         = (PREQBLK pReqBlk)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

IOCFUNC IocSetEmulState(PREQBLK pReqBlk)
{
  USHORT emul;

  emul = *((PUSHORT)pReqBlk->ioctl.pParms);
  if (emul > TDI_EMUL_MAX)
  {                                   /* parms error                         */
    pReqBlk->status = REQE_PARM;
  }
  else
  {                                   /* set emulation                       */
    /* Disable */
    SetEmulState(pCurrSgcb->EmulState = emul);
    /* Enable */
  }
}                                     /* IocSetEmulState                     */


/****************************************************************************
 *
 * FUNCTION NAME = IocGetEmulState
 *
 * DESCRIPTION   =
 *   Called from : ReqIoctl (seg3)
 *
 *
 * INPUT         = (PREQBLK pReqBlk)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

IOCFUNC IocGetEmulState(PREQBLK pReqBlk)
{
  /* copy to data */
  *((PUSHORT)pReqBlk->ioctl.pData) = pCurrSgcb->EmulState;
}                                     /* IocGetEmulState                     */


/****************************************************************************
 *
 * FUNCTION NAME = IocReadEventQueue
 *
 * DESCRIPTION   =
 *   Called from : ReqIoctl (seg3)
 *
 *
 * INPUT         = (PREQBLK pReqBlk)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

IOCFUNC IocReadEventQueue(PREQBLK pReqBlk)
{
  USHORT Options;
  USHORT ret;
  PLINFOSEG pLis;

#define  POPTIONS          ((PUSHORT)pReqBlk->ioctl.pParms)
#define  PEVENTDATA        ((PTDIEVENTDATA)pReqBlk->ioctl.pData)

  cli();

  if (Idc_QueryConfig(&DevData) || !(DevData.touch_status & TS_CALIBRATED))
  {                                   /* Fail if not calibrated              */

    /* use seek error to represent not calibrated*/
    pReqBlk->status = REQE_SEEK;      /* not calibrated                      */
    goto IocReadEventExit;
  }

  if (pCurrSgcb->DevStatus.eq_busy)
  {                                   /* already busy                        */
    pReqBlk->status = REQE_GENF;
    goto IocReadEventExit;
  }

  if ((Options = *POPTIONS) & ~TDI_READ_BITS)
  {                                   /* invalid parameters                  */
    pReqBlk->status = REQE_PARM;
    goto IocReadEventExit;
  }
  if (pCurrSgcb->Eq_Size == 0 && (Options & TDI_READ_WAIT))
  {                                   /* queue empty & wait requested        */
    pCurrSgcb->DevStatus.blocked = 1;
    pReqBlk->status |= REQS_BUSY;
    pCurrSgcb->Eq_Pid = SemPid;
    DHSemClear(&CmdSem);              /* release ram sem control             */

    /* cli(); */                      /* int flag not affected by above call */
    SemPid = 0;                       /* clear sem ownership pid             */
    do
    {                                 /* reblock                             */
      /*
      ** The address of event queue start is near but it is
      ** in the same segment as pCurrSgcb.
      */
      ret = DHBlock((PEVENT)pCurrSgcb->Eq_Start,
                    -1l,              /* inhibit timeout                     */
                    0                 /* interruptable                       */
                   );
      cli();                          /* re-disable ints after block         */

      if (ret)
      {                               /* block: unusual wakeup               */
        /* assume interrupted*/
        pReqBlk->status = REQE_CHARINT;
        goto IocReadEventExit;
      }
    }  while (pCurrSgcb->Eq_Size == 0);

    /* Get cmd semapore again after block */
    if (DHSemRequest(&CmdSem, -1))
    {
      SemPid = 0;
      pReqBlk->status = REQE_GENF;
      goto IocReadEventExit;
    }

    /* Get Local Info seg */
    if ((pLis = *(PLINFOSEG FAR *)DHGetDOSVar(GDV_LocalInfoSeg)) == NULL)
    {
      pReqBlk->status = REQE_GENF;
      goto IocReadEventExit;
    }

    CurrSess = pLis->sgCurrent;
    SemPid = pLis->pidCurrent;
    pCurrSgcb->DevStatus.blocked = 0;
    pCurrSgcb->Eq_Pid = 0;
    pReqBlk->status &= ~REQS_BUSY;
  }                                   /* if - wait for event                 */

  /* Update returned count before data is read or peeked*/
  if ((PEVENTDATA->cEvents = pCurrSgcb->Eq_Size) != 0)
  {                                   /* some data to read                   */
    pCurrSgcb->DevStatus.eq_busy = 1;
    QueueRead((PEVENT)&(PEVENTDATA->Status), pCurrSgcb,
              !!(Options & TDI_READ_PEEK));
    pCurrSgcb->DevStatus.eq_busy = 0;
  }

IocReadEventExit:
  sti();
}                                     /* IocReadEventQueue                   */


/****************************************************************************
 *
 * FUNCTION NAME = SetEmulState
 *
 * DESCRIPTION   =
 *
 *
 * INPUT         = (USHORT State)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

STATIC VOID NEAR PASCAL SetEmulState(USHORT State)
{
  if (CurrSess == FgndSess)
  {                                   /* This session is in foreground       */
    /* Update DDDD */
    Idc_SetEmulation(State);
  }
}                                     /* SetEmulState                        */


/****************************************************************************
 *
 * FUNCTION NAME = SgControl
 *
 * DESCRIPTION   = Session Switch Notification (Ioctl 11,41)
 *   Called from : NewStratEntry (seg3)
 *
 *
 * INPUT         = (PREQBLK pReqBlk) - pointer to request block
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE - via request block
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

STATIC IOCFUNC SgControl(PREQBLK pReqBlk)
{
  PNOTIFY pNotify;
  PSGCB pSgcb;

  pNotify = pReqBlk->ioctl.pParms;
  if (pNotify->action == SESA_END)
  {                                   /* end of a session switch             */
    if (pNotify->psw_type_in == SEST_PROT_FS)
    {
      if ((pSgcb = FindCb(pNotify->psw_sess_in)) == NULL)
      {                               /* Find, failed                        */
        pReqBlk->status = REQE_GENF;
      }
      else
      {                               /* FS CB found                         */
        /* Update emulation settings */
        Idc_SetEmulation(pSgcb->EmulState);
        Idc_SetBeep(1);               /* turn on emul beeper                 */
      }
      pFgndSgcb = pSgcb;
    }
    else
    {
      pFgndSgcb = NULL;
    }

    FgndSess = pNotify->psw_sess_in;
  }
  else
    if (pNotify->action == SESA_TERM)
    {                                 /* terminate a session                 */
      if (pNotify->term_type_out == SEST_PROT_FS)
      {
        if (pNotify->term_sess_out == FgndSess)
        {
          pFgndSgcb = NULL;
        }

        if ((pSgcb = FindCb(pNotify->term_sess_out)) == NULL)
        {                             /* Find, failed                        */
          pReqBlk->status = REQE_GENF;
        }
        else
        {                             /* found ok                            */
          if (pSgcb->Chain_Size == 0)
          {                           /* no monitor chains                   */
            if (FreeSgcb(pNotify->term_sess_out))
            {                         /* Free, failed                        */
              pReqBlk->status = REQE_GENF;
            }
          }
        }
      }
      else
        if (pNotify->term_type_out == SEST_REAL_FS)
        {
          ;
        }
    }
    else
      if (pNotify->action == SESA_CREATE)
      {                               /* create a session                    */
        if (pNotify->creat_type_in == SEST_PROT_FS)
        {
          /*
          ** If a full screen session check to see if
          ** control block already allocated. This could
          ** be if a monitor has already been registered
          ** or it is one of the preallocated SGs. (0,1,2)
          */
          if (FindCb(pNotify->creat_sess_in) == NULL)
          {                           /* Not found so create a CB            */
            if (SgCreate(pNotify->creat_sess_in,
                         pNotify->creat_type_in,
                         pNotify->action))
            {                         /* Create, failed                      */
              pReqBlk->status = REQE_GENF;
            }
          }
        }
        else
          if (pNotify->creat_type_in == SEST_REAL_FS)
            ;
      }

  #if 0                         /* ???                                       */
    else
      if (pNotify->action == SESA_CHANGE)
      {                                 /* change session type               */
        if (pNotify->n_outgoing_type == SEST_N_REAL_WIN &&
            pNotify->n_incoming_type == SEST_N_REAL_FS)
        {                               /* DosBox: Win to FS                 */
          if (SgCreate(pNotify->n_incoming_sess,
                       pNotify->n_incoming_type,
                       pNotify->action))
            /* Create, failed */
            pReqBlk->status = REQE_GENF;
        }
        else
          if (pNotify->n_outgoing_type == SEST_N_REAL_FS &&
              pNotify->n_incoming_type == SEST_N_REAL_WIN)
          {                             /* DosBox: FS to Win                 */
            if (pNotify->n_outgoing_sess == FgndSess)
            {
              pFgndSgcb = NULL;
            }

            if (FreeSgcb(pNotify->n_outgoing_sess))
              /* Free, failed */
              pReqBlk->status = REQE_GENF;
          }
      }
  #endif
  /* ELSE - Ignore all unrecognised operations */
}                                     /* SgControl                           */


/****************************************************************************
 *
 * FUNCTION NAME = SgCreate
 *
 * DESCRIPTION   =
 *   Called from : SgControl (seg3)
 *
 *
 * INPUT         = (USHORT sess,USHORT sess_type,USHORT action)
 *                  USHORT  incoming session id (BL)
 *                  USHORT  session type (BH)
 *                  USHORT  session switch action (DX)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = OK
 *
 * RETURN-ERROR  = ERROR
 *
 ****************************************************************************/

STATIC USHORT NEAR PASCAL SgCreate(USHORT sess, USHORT sess_type, USHORT action)
{
  PSGCB pSgcb;

  if ((pSgcb = AllocCb((sess_type == SEST_PROT_FS) ?
                         sizeof(SGCB) + MaxEQLen * sizeof(EVENT) :
                         0,           /* VDM alloc not supported             */
                       sess, sess_type)) == NULL)
    return (ERROR);

  if (sess_type == SEST_PROT_FS)
  {
    /*
    ** The event q is allocated at the end of CB
    ** & stored near as it is in same segment as pSgcb
    ** because they are allocated as a whole.
    */
    InitFsCb(pSgcb, (NPEVENT)(OFFSETOF(pSgcb) + sizeof(SGCB)));
  }
  else
    InitVdmCb(sess, action, pSgcb);

  return (OK);
}                                     /* SgCreate                            */


/****************************************************************************
 *
 * FUNCTION NAME = MonitorHandler
 *
 * DESCRIPTION   = Monitor Handler Notification Routine
 *   Called from : Kernel monitor dispatcher
 *                 (proc registered with DevHlp Monitor Create call)
 *
 *
 * INPUT         = (USHORT reg)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

STATIC VOID FAR CDECL SAVEREGS LOADDS MonitorHandler(USHORT reg)
{
  PMONBUF pMonBuf;
  PMONBUF pMB;
  USHORT fFound = FALSE;
  USHORT REG sess;
  PSGCB pSgcb;                        /* local copy                          */

#define  SOFF(p,s,e)       ((s FAR *)((PBYTE)p-FIELDOFFSET(s,e)))

#if 0                                 /* ???                                 */
  Idc_DisableDevice();

  pMB = pMonBuf = (PMONBUF)MAKEP(_ES(reg), _SI(reg));

  if (!(pMonBuf->MFlags&4))           /* flush (same as DevStatus flags)     */
  {                                   /* not a flush record                  */
    pMB = &pFgndSgcb->MonBuf;
    if (pMB == pMonBuf)
    {                                 /* found 1st time                      */
      fFound = TRUE;
    }
    else
    {                                 /* not found 1st time                  */
      for (sess = 0; sess < NumSess; ++sess)
      {
        pMB = &FindCb(sess)->MonBuf;
        if (pMB == pMonBuf)
        {                             /* found                               */
          fFound = TRUE;
          break;
        }
      }                               /* for                                 */
    }                                 /* if - found 1st time                 */

    if (fFound == TRUE)
    {                                 /* found at all                        */
      pSgcb = SOFF(pMB, SGCB, MonBuf);
      if (!pSgcb->DevStatus.eq_busy)
      {                               /* not busy                            */
        pSgcb->DevStatus.eq_busy = 1;
        QueueWrite(pSgcb, &pMonBuf->Event);
        pSgcb->DevStatus.eq_busy = 0;
      }                               /* if - not busy                       */
    }                                 /* if - found at all                   */
  }                                   /* if - not a flush record             */
  else
  {                                   /* flush record                        */
    /* reset flush flag */
    SOFF(pMB, SGCB, MonBuf)->DevStatus.flush = 0;
  }

  Idc_EnableDevice();
#undef   SOFF
#endif
}                                     /* MonitorHandler                      */


/****************************************************************************
 *
 * FUNCTION NAME = Ring0Init
 *
 * DESCRIPTION   = Ring 0 Initialisation
 *   Called from : NewStratEntry (seg3)
 *                 PddEntry (seg3)
 *
 *
 * INPUT         = (VOID)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

STATIC VOID NEAR PASCAL Ring0Init(VOID)
{
  if ((GetCS()&3) == 0)
  {                                   /* now running in ring0                */
    InitStage = 2;
    if (Idc_QueryConfig(&DevData))
      InitStage = -1;
    else
    {
      /* Set emulation state for vtouch driver from config parms.            */
      /* !!! DevData.mouse_status &= ~MS_REAL_EMUL; */   /* reset bit!       */
      if (DefaultEmul)
      {                            /* set bit if default emulation enabled   */
        DevData.mouse_status |= (MS_REAL_EMUL | MS_PROT_EMUL);
      }

      if (Idc_ReadEnable(&IntPkt))
        /* read enable failed */
        InitStage = -1;
      else
        /* read enable ok */
        Idc_EnableDevice();
    }                                 /*                                     */
  }                                   /* if - ring0                          */
}                                     /* Ring0Init                           */


/****************************************************************************
 *
 * FUNCTION NAME = AccessCheck
 *
 * DESCRIPTION   =
 *   Called from : ReqIoctl (seg3)
 *
 *
 * INPUT         = (PREQBLK pReqBlk,USHORT IocIndex)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = FALSE - access ok
 *
 * RETURN-ERROR  = TRUE  - access failed
 *
 ****************************************************************************/

STATIC USHORT NEAR PASCAL AccessCheck(PREQBLK pReqBlk, USHORT IocIndex)
{
  return ( CheckPkt( pReqBlk->ioctl.pParms,
                     IocTable[IocIndex].ParmsCheck,
                   #if DD_LEVEL >= 2
                     pReqBlk->ioctl.cbParms
                   #else
                     0
                   #endif
                   ) ||
           CheckPkt( pReqBlk->ioctl.pData,
                     IocTable[IocIndex].DataCheck,
                   #if DD_LEVEL >= 2
                     pReqBlk->ioctl.cbData
                   #else
                     0
                   #endif
                   ));
}                                     /* AccessCheck                         */


/****************************************************************************
 *
 * FUNCTION NAME = CheckPkt
 *
 * DESCRIPTION   = Check parms & data pointers
 *   Called from : AccessCheck
 *
 *
 * INPUT         = (PVOID pMem,USHORT check,USHORT len)
 *                  PVOID   pointer to data to be checked
 *                  USHORT  check flags
 *                  USHORT  length of data to be checked if dd level >= 2
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = FALSE - access ok
 *
 * RETURN-ERROR  = TRUE  - access failed
 *
 ****************************************************************************/

STATIC USHORT NEAR PASCAL CheckPkt(PVOID pMem, USHORT check, USHORT len)
{
  if (check & ACC_CHECK)
  {                                   /* some checking to be done            */
    /* null selector check */
    if ((check & ACC_NULLOK) && (SELECTOROF(pMem) & ~7) == 0)
    {                                 /* null selector supplied & allowed    */
      return (FALSE);                 /* ok                                  */
    }

    /*
    ** If level-2 device driver then use supplied length
    ** in reqblk & not from ioctl table
    */
    if (!(check & ACC_LVL2) && (len = (check & ACC_BMASK)) == 0)
    {                                 /* zero length & not level-2           */

      /* verify access to length */
      if (DHVerifyAccess(pMem, sizeof(USHORT), /*(UCHAR)!!(check & ACC_WRITE)*/
                         DH_VA_RD))
        return (TRUE);                /* failed                              */

      /* get length from 1st short in struc */
      len = *(PUSHORT)(pMem);
    }                                 /* if - zero len                       */

    /* verify memory access to parms/data */
    if (DHVerifyAccess( pMem, len,
                        (UCHAR)((check & ACC_WRITE) ? DH_VA_RW : DH_VA_RD)))
      return (TRUE);                  /* failed access check                 */
  }                                   /* if - some checking to be done       */
  else
    /* no checking to be done*/
    return (FALSE);                   /* ok                                  */
}                                     /* CheckPkt                            */


/****************************************************************************
 *
 * FUNCTION NAME = QueueRead
 *
 * DESCRIPTION   =
 *   Called from : ioc_63 (seg3)
 *
 *
 * INPUT         = (PEVENT pEvent,PSGCB pSgcb,USHORT fPeek)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = event
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

STATIC VOID NEAR PASCAL QueueRead(PEVENT pEvent, PSGCB pSgcb, USHORT fPeek)
{
  register SGCB _based((_segment)pSgcb) * pCb =
                  (SGCB _based((_segment)pSgcb)*)OFFSETOF(pSgcb);

  *pEvent = *pCb->Eq_Head;            /* get current event                   */
  if (!fPeek)
  {                /* not peeking queue, so update: size, head & tail ptrs   */
    ++pCb->Eq_Head;
    /* MaxEqLen is a count of EVENTs not total bytes in Q                    */
    --pCb->Eq_Size;

  #ifndef SETQ
    if (pCb->Eq_Head >= pCb->Eq_Start + MaxEQLen)
  #else
    if (pCb->Eq_Head >= pCb->Eq_Start + pCb->QueueSize)
  #endif

    /* wrap queue ptr */
    pCb->Eq_Head = pCb->Eq_Start;
  }                                   /* if - not peeking                    */
}                                     /* QueueRead                           */


/****************************************************************************
 *
 * FUNCTION NAME = FlushMonitorChain
 *
 * DESCRIPTION   =
 *   Called from : ReqInputFlush (seg3)
 *                 ReqClose (seg3)
 *                 ioc_5c (seg3)
 *
 *
 * INPUT         = (VOID)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = FALSE   ok
 *
 * RETURN-ERROR  = TRUE    flush request failed
 *
 ****************************************************************************/

STATIC USHORT NEAR PASCAL FlushMonitorChain(VOID)
{
  USHORT ret = OK;

  pCurrSgcb->DevStatus.eq_busy = 1;

  flush(pCurrSgcb);

  if (pCurrSgcb->Chain_Size > 0)
  {                                   /* some chains to flush                */
    pCurrSgcb->DevStatus.flush = 1;
    if ((ret = DHMonFlush(pCurrSgcb->Chain_Hdle)))
    {                                 /* flush failed                        */
      pCurrSgcb->DevStatus.flush = 0;
    }
  }

  pCurrSgcb->DevStatus.eq_busy = 0;
  return (ret);
}                                     /* FlushMonitorChain                   */


/****************************************************************************
 *
 * FUNCTION NAME = Idc_EnableDevice
 *
 * DESCRIPTION   =
 *   Called from : ReqOpen
 *                 ReqClose
 *                 ioc_59
 *                 ioc_5c
 *                 ioc_51
 *                 ioc_5d
 *                 ioc_56
 *                 ioc_57
 *                 ioc_58
 *                 ioc_5a
 *                 ioc_55
 *                 MonitorHandler
 *                 PddRegisterVdd
 *                 PddSetScreenSize
 *                 Ring0Init
 *
 *
 * INPUT         = (VOID)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

STATIC VOID NEAR PASCAL SAVEREGS Idc_EnableDevice(VOID)
{
  VOID(FAR *LocalIdcProtEntry)() = DD_Idc.ProtEntry;

  _asm
  {
        push    ds                    /* our data seg                        */
        pop     es
        mov     ax, 4
        mov     ds, DD_Idc.ProtDS     /* dddd data seg                       */
        call    LocalIdcProtEntry     /* call dddd                           */
  }                                   /* _asm                                */
}                                     /* Idc_EnableDevice                    */


/****************************************************************************
 *
 * FUNCTION NAME = Idc_DisableDevice
 *
 * DESCRIPTION   =
 *   Called from : ReqOpen
 *                 ReqClose
 *                 ioc_59
 *                 ioc_5c
 *                 ioc_51
 *                 ioc_5d
 *                 ioc_56
 *                 ioc_57
 *                 ioc_58
 *                 ioc_5a
 *                 ioc_55
 *                 MonitorHandler
 *                 PddRegisterVdd
 *                 PddSetScreenSize
 *
 *
 * INPUT         = (VOID)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

STATIC VOID NEAR PASCAL SAVEREGS Idc_DisableDevice(VOID)
{
  VOID(FAR *LocalIdcProtEntry)() = DD_Idc.ProtEntry;

  _asm
  {
        push    ds                    /* our data seg                        */
        pop     es
        mov     ax, 5
        mov     ds, DD_Idc.ProtDS     /* dddd data seg                       */
        call    LocalIdcProtEntry     /* call dddd                           */
  }                                   /* _asm                                */
}                                     /* Idc_DisableDevice                   */


/****************************************************************************
 *
 * FUNCTION NAME = Idc_QueryConfig
 *
 * DESCRIPTION   =
 *
 *
 * INPUT         = (PCONFDAT pConfDat)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

STATIC USHORT NEAR PASCAL SAVEREGS Idc_QueryConfig(PCONFDAT pConfDat)
{
  USHORT ret_val;

  VOID(FAR *LocalIdcProtEntry)() = DD_Idc.ProtEntry;

  _asm
  {
        /* NB. pConfDat must be in same seg as DD_Idc & must be the default  */
        /*     data seg                                                      */

        mov     ax, 1
        les     di, pConfDat          /* ptr to struc to be filled in        */
        mov     ds, DD_Idc.ProtDS     /* dddd data seg                       */
        call    LocalIdcProtEntry     /* call dddd                           */
        jc      idc_q_conf_exit       /* jic error                           */

        xor     ax, ax                /* no error                            */

idc_q_conf_exit:
        mov     ret_val, ax
  }                                   /* _asm                                */

  return (ret_val);
}                                     /* Idc_QueryConfig                     */


/****************************************************************************
 *
 * FUNCTION NAME = Idc_ReadEnable
 *
 * DESCRIPTION   =
 *
 *
 * INPUT         = (PINTPKT pIntPkt)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

STATIC USHORT NEAR PASCAL SAVEREGS Idc_ReadEnable(PINTPKT pIntPkt)
{
  USHORT ret_val;

  VOID(FAR *LocalIdcProtEntry)() = DD_Idc.ProtEntry;

  _asm
  {
        /* NB. IntPkt must be in same seg as DD_Idc & must be the default    */
        /*     data seg                                                      */

        mov     ax, 2
        les     di, pIntPkt           /* far ptr to shared int packet        */
        mov     ds, DD_Idc.ProtDS     /* dddd data seg                       */
        call    LocalIdcProtEntry     /* call dddd                           */
        jc      idc_rd_en_exit        /* jif error                           */

        xor     ax, ax                /* no error                            */

idc_rd_en_exit:
        mov     ret_val, ax
  }                                   /* _asm                                */

  return (ret_val);
}                                     /* Idc_ReadEnable                      */


/****************************************************************************
 *
 * FUNCTION NAME = Idc_SetEmulation
 *
 * DESCRIPTION   =
 *
 *
 * INPUT         = (USHORT State)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

STATIC USHORT NEAR PASCAL SAVEREGS Idc_SetEmulation(USHORT State)
{
  USHORT ret_val;

  VOID(FAR *LocalIdcProtEntry)() = DD_Idc.ProtEntry;

  _asm
  {
        mov     ax, 6                 /* function                            */
        mov     si, State             /* emulation setting                   */
        mov     ds, DD_Idc.ProtDS     /* dddd data seg                       */
        call    LocalIdcProtEntry     /* call dddd                           */
        jc      idc_set_emul_exit     /* jic error                           */

        xor     ax, ax                /* no error                            */

idc_set_emul_exit:
        mov     ret_val, ax
  }                                   /* _asm                                */

  return (ret_val);
}                                     /* Idc_SetEmulation                    */


/****************************************************************************
 *
 * FUNCTION NAME = Idc_SetBeep
 *
 * DESCRIPTION   =
 *
 *
 * INPUT         = (USHORT State)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

STATIC USHORT NEAR PASCAL SAVEREGS Idc_SetBeep(USHORT State)
{
  USHORT ret_val;

  VOID(FAR *LocalIdcProtEntry)() = DD_Idc.ProtEntry;

  _asm
  {
        mov     ax, 7                 /* function                            */
        mov     si, State             /* emulation setting                   */
        mov     ds, DD_Idc.ProtDS     /* dddd data seg                       */
        call    LocalIdcProtEntry     /* call dddd                           */
        jc      idc_set_beep_exit     /* jic error                           */

        xor     ax, ax                /* no error                            */

idc_set_beep_exit:
        mov     ret_val, ax
  }                                   /* _asm                                */

  return (ret_val);
}                                     /* Idc_SetBeep                         */


/****************************************************************************
 *
 * FUNCTION NAME = InitVdmCb
 *
 * DESCRIPTION   =
 *   Called from : SgCreate (seg3)
 *
 *
 * INPUT         = (USHORT sess,USHORT action,PSGCB pSgcb)
 *                  USHORT  session id (BL)
 *                  USHORT  session action (DX)
 *                  PSGCB   control block to init
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

STATIC VOID NEAR PASCAL InitVdmCb(USHORT sess, USHORT action, PSGCB pSgcb)
{
  if (action == SESA_CREATE)
  {
    ;
  }
  else
    if (action == SESA_CHANGE)
    {
      ;
    }
}                                     /* InitVdmCb                           */


/****************************************************************************
 *
 * FUNCTION NAME = InitFsCb
 *
 * DESCRIPTION   =
 *   Called from : ioc_10_40 (seg3)
 *                 SgCreate (seg3)
 *
 *
 * INPUT         = (PSGCB pSgcb,NPEVENT pEq)
 *                  PSGCB   control block to init
 *                  NPEVENT event queue ptr
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

extern VOID FAR PASCAL InitFsCb(PSGCB pSgcb, NPEVENT pEq)
{
  pSgcb->Hdle_Count        = 0;
  pSgcb->Eq_Size           = 0;
  pSgcb->Eq_Start          = pEq;
  pSgcb->QueueSize         = DefQSize;
  pSgcb->Eq_Pid            = 0;
  pSgcb->DevStatus.eq_busy = 0;
  pSgcb->DevStatus.blocked = 0;
  pSgcb->DevStatus.flush   = 0;
  pSgcb->Chain_Size        = 0;
  pSgcb->Chain_Hdle        = 0;
  pSgcb->EmulState         = DefaultEmul;
}                                     /* InitFsCb                            */


/****************************************************************************
 *
 * FUNCTION NAME = SetCBDefaults
 *
 * DESCRIPTION   =
 *
 *
 * INPUT         = (PSGCB pSgcb)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

STATIC VOID NEAR PASCAL SetCBDefaults(PSGCB pSgcb)
{
  pSgcb->CoordSys.XMin = 0;
  pSgcb->CoordSys.XMax = 4095;
  pSgcb->CoordSys.YMin = 0;
  pSgcb->CoordSys.YMax = 4095;
  pSgcb->CoordSys.ZMin = 0;
  pSgcb->CoordSys.ZMax = 255;
  pSgcb->CoordSys.XHys = 500;
  pSgcb->CoordSys.YHys = 500;

  pSgcb->SelMech.Type        = DefSelm.Type;
  pSgcb->SelMech.NumPoints   = DefSelm.NumPoints;
  pSgcb->SelMech.Tolerance   = DefSelm.Tolerance;
  pSgcb->SelMech.SearchLimit = DefSelm.SearchLimit;
}                                     /* SetCBDefaults                       */


/****************************************************************************
 *
 * FUNCTION NAME = FindCb
 *
 * DESCRIPTION   =
 *   Called from : NewStratEntry (seg3)
 *                 ReqClose (seg3)
 *                 MonitorReg (seg3)
 *                 SgControl (seg3)
 *                 SgSwitchStart (seg3)
 *                 SgSwitchEnd (seg3)
 *                 MonitorHandler (seg3)
 *                 PddEntry (seg3)
 *
 *
 * INPUT         = (USHORT sess) - session id (BL)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = PSGCB  far (allocated) ptr to a session control block (DS:SI)
 *
 * RETURN-ERROR  = NULL   error (CY)
 *
 ****************************************************************************/

STATIC PSGCB NEAR PASCAL FindCb(USHORT sess)
{
  USHORT fFound;
  PCBTAB pCbTab;

  pCbTab = FindCbPtr(sess, 1, &fFound);

  if (!fFound)
    return (NULL);                    /* error, not found                    */

  return (pCbTab->pSgcb);
}                                     /* FindCb                              */


/****************************************************************************
 *
 * FUNCTION NAME = FindCbPtr
 *
 * DESCRIPTION   =
 *   Called from : FindCb (seg3)
 *                 AllocCb (seg3)
 *                 FreeSgcb (seg3)
 *
 *
 * INPUT         = (USHORT sess,USHORT fFS,PUSHORT pfFound)
 *                  USHORT  session id (BL)
 *                  USHORT  FS flag (BH)
 *                           0 - not full screen, overrides if
 *                               sess number < max sessions
 *                          !0 - full screen & session < max
 *                  PUSHORT pfFound - ptr to found flag
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = PCBTAB  far (allocated) ptr to control block table entry
 *                         (DS:SI)
 *
 * RETURN-ERROR  = USHORT  *pfFound: (CY if not found)
 *                  TRUE   if found
 *                  FALSE  if not found
 *
 ****************************************************************************/

STATIC PCBTAB NEAR PASCAL FindCbPtr(USHORT sess, USHORT fFS, PUSHORT pfFound)
{
  PCBTAB pCbTab;
  USHORT index;

  if (sess < NumSess && fFS != 0)
  {                                   /* full screen session                 */
    pCbTab = &FsCbTable[sess];
    if (SELECTOROF(pCbTab->pSgcb) == 0)
    {                                 /* not found                           */
      *pfFound = FALSE;
      return (pCbTab);
    }
  }
  else
  {                                   /* not full screen session             */
    pCbTab = OtherCbTable;
    for (; ; )
    {                                 /* search all blocks                   */
      for (index = 1; index < VSG_BLK; ++index, ++pCbTab)
      {                               /* search current block                */
        if (pCbTab->sess == (UCHAR)sess)
          break;                      /* found sgcb                          */
      }

      if (index != VSG_BLK)
        break;                        /* found sgcb                          */

      if (SELECTOROF(pCbTab->pSgcb) == 0)
      {                               /* end of list & not found             */
        *pfFound = FALSE;
        return (pCbTab);
      }

      /* Get next block in list */
      pCbTab = (PCBTAB)pCbTab->pSgcb;
    }                                 /* for - ever                          */
  }                                   /* if                                  */

  /* found */
  *pfFound = TRUE;

  return (pCbTab);
}                                     /* FindCbPtr                           */


/****************************************************************************
 *
 * FUNCTION NAME = AllocCb
 *
 * DESCRIPTION   = Allocate a control block, virtual or full screen
 *   Called from : MonitorReg (seg3)
 *                 SgCreate (seg3)
 *
 *
 * INPUT         = (USHORT Size,USHORT sess,USHORT sess_type)
 *                  USHORT allocation size in bytes (CX)
 *                  USHORT session id (BL)
 *                  USHORT session type (BH)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = PSGCB   ptr to new sgcb for session (DS:SI)
 *
 * RETURN-ERROR  = NULL    if error (CY)
 *
 ****************************************************************************/

STATIC PSGCB NEAR PASCAL AllocCb(USHORT Size, USHORT sess, USHORT sess_type)
{
  PMEM pMem;
  USHORT count;
  USHORT fFound;
  PCBTAB pCbTab;

  pCbTab = FindCbPtr(sess, sess_type, &fFound);
  if (!fFound)
  {                                   /* not already found                   */
    if (sess >= NumSess)
    {                                 /* not full screen session             */

      /* Find vdm control block, starting at first & moving thru             */
      /*   linked list of blocks                                             */
      pCbTab = FindCbPtr(0, 0, &fFound);

      if (!fFound)
      {                               /* not found                           */
        /* allocate new table block   */
        if ((pMem = AllocMem(sizeof(CBTAB) * VSG_BLK)) == NULL)
          return (NULL);

        /* save addr of new block in last one found */
        pCbTab->linSgcb = pMem->Lin;
        pCbTab->pSgcb = (PSGCB)pMem->Virt;

        /* get new entry, from list */
        pCbTab = (PCBTAB)pCbTab->pSgcb;

        /* initialise rest of new block */
        for (count = 0; count < VSG_BLK; ++count)
        {
          pCbTab[count].sess = 0;
          pCbTab[count].pSgcb = NULL;
        }
      }                               /* if - vdm block not found            */
    }                                 /* if - not full screen                */

    /* Allocate new control block, FS or Virt, of required size              */
    if ((pMem = AllocMem(Size)) == NULL)
      return (NULL);

    pCbTab->sess    = (UCHAR)sess;
    pCbTab->type    = (UCHAR)sess_type;
    pCbTab->pSgcb   = (PSGCB)pMem->Virt;
    pCbTab->linSgcb = pMem->Lin;
  }                                   /* if - not found                      */

  return (pCbTab->pSgcb);
}                                     /* AllocCb                             */


/****************************************************************************
 *
 * FUNCTION NAME = FreeSgcb
 *
 * DESCRIPTION   = Free Screen Group Control Block Memory
 *   Called from : SgControl (seg3)
 *
 *
 * INPUT         = (USHORT Sess)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = USHORT  Failure (CY)
 *
 ****************************************************************************/

STATIC USHORT NEAR PASCAL FreeSgcb(USHORT Sess)
{
  PCBTAB pCbTab;
  USHORT fFound;

  pCbTab = FindCbPtr(Sess, 1, &fFound);

  if (!fFound)
    return (ERROR);                   /* not found                           */

  if (DHVMFree(pCbTab->linSgcb))
    return (ERROR);

  pCbTab->sess  = 0;
  pCbTab->pSgcb = NULL;

  return (OK);
}                                     /* FreeSgcb                            */


/****************************************************************************
 *
 * FUNCTION NAME = AllocMem
 *
 * DESCRIPTION   = Allocate memory
 *   Called from : AllocCb (seg3)
 *
 *
 * INPUT         = (USHORT Size)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = PMEM    ptr to memory info
 *
 * RETURN-ERROR  = NULL    failed (CY)
 *
 ****************************************************************************/

STATIC PMEM NEAR PASCAL AllocMem(USHORT Size)
{
  static MEM Mem;

  if (DHVMAlloc(DH_VMA_VIRTUAL | DH_VMA_FIXED, Size, -1l, &Mem))
    return (NULL);                    /* fail                                */

  return (&Mem);
}                                     /* AllocMem                            */


/****************************************************************************
 *
 * FUNCTION NAME = NewPddEntry
 *
 * DESCRIPTION   = VDD IDC entry
 *   Called from : Virtual DD via 16:32 IDC
 *
 *
 * INPUT         = (ULONG ulFunc,PUSHORT pIBuff,PUSHORT pOBuff)
 *                  ULONG   ulFunc  function code
 *                  PUSHORT pIBuff  input buffer (or address for register)
 *                  PUSHORT pOBuff  output buffer (or address for register)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

extern USHORT FAR LOADDS SAVEREGS NewPddEntry(ULONG ulFunc, PUSHORT pIBuff,
                                               PUSHORT pOBuff)
{
  PSGCB pSgcb;

  if (InitStage == 1)
    Ring0Init();

  if (InitStage != 2 || ulFunc > VDMTABMAX)
    /*     init or requested function out of range                           */
    return (FALSE);                   /* fail                                */

  /* check data size to be read, if any                                      */
  if (VdmTable[ulFunc].DataSize != 0 && VdmTable[ulFunc].DataSize != pIBuff[0])
    /* size not correct                                                      */
    return (FALSE);                   /* fail                                */

  /* get sgcb addr where flaged as being supplied                            */
  if (VdmTable[ulFunc].fSess && (pSgcb = FindCb(pIBuff[1])) == NULL)
    return (TRUE);

  switch ((USHORT)ulFunc)
  {
    case 0 :
      return (PddRegisterVdd(pIBuff, pOBuff));

    case 1 :
      return (PddQueryConfig(pOBuff));

    case 2 :
      return (PddSetEmul(pIBuff));

    case 3 :
      return (PddDisable());

    case 4 :
      return (PddSetExclAcc(pIBuff));

  #ifdef DEBUG
    default  :
      panic(__FILE__, __LINE__,
            "PddEntry: function number (%lu), out of range", ulFunc);
  #endif
  }                                   /* switch                              */
}                                     /* NewPddEntry                         */


/****************************************************************************
 *
 * FUNCTION NAME = PddRegisterVdd
 *
 * DESCRIPTION   = Called when Vdd calls VDHOpenPDD()
 *   Called from : PddEntry (seg3) via VdhOpenPdd()
 *   Usage:        Success = PddEntry( 0, VddEntrySelector, VddEntryOffset);
 *
 *
 * INPUT         = (PUSHORT pIBuff,PUSHORT pOBuff)
 *                  USHORT  pIBuff.off  VDD's CS
 *                  USHORT  pIBuff.sel  zero
 *                  USHORT  pOBuff.off  low 16-bits of EIP for VDD entry point
 *                  USHORT  pOBuff.sel  high 16-bits of EIP for VDD entry point
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

STATIC VDMFUNC PddRegisterVdd(PUSHORT pIBuff, PUSHORT pOBuff)
{
  Idc_DisableDevice();
  TouVddEntry.off32 = (ULONG)pOBuff;
  TouVddEntry.sel16 = LOUSHORT((LONG)pIBuff);
  fVdmEnabled = 1;
  Idc_EnableDevice();
  return (TRUE);                      /* ok                                  */
}                                     /* PddRegisterVdd                      */


/****************************************************************************
 *
 * FUNCTION NAME = PddQueryConfig
 *
 * DESCRIPTION   = Copy device config data to a Vdd 16:16 ptr
 *   Called from : PddEntry (seg3) [QueryType(&TouHardware)]
 *   Usage:        Success = PddEntry( 1, NULL, &ParmsAddr);
 *
 *
 * INPUT         = (PUSHORT pOBuff)
 *
 * OUTPUT        = Configuration data:
 *                         USHORT  size = 7
 *                         UCHAR   irq
 *                         USHORT  mouse status
 *                         USHORT  touch status
 *                 BOOL success (AX)
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/


STATIC VDMFUNC PddQueryConfig(PUSHORT pOBuff)
{
  if (((PCONFDAT)pOBuff)->length != sizeof(CONFDAT))
    return (FALSE);                   /* fail                                */

  /* Get latest settings */
  if (Idc_QueryConfig(&DevData))
    return (FALSE);                   /* fail                                */

  *((PCONFDAT)pOBuff) = DevData;

  return (TRUE);                      /* ok                                  */
}                                     /* PddQueryType                        */


/****************************************************************************
 *
 * FUNCTION NAME = PddSetEmul
 *
 * DESCRIPTION   = Set emulation state
 *   Called from :  PddEntry (seg3)
 *   Usage:         Success = PddEntry( 2, &DataAddr, NULL);
 *
 *
 * INPUT         = (PUSHORT pIBuff)
 *                  Emulation data:
 *                    USHORT  size = 3
 *                    UCHAR   emul state (0 - off, 1 - absolute, 2 - glass)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

STATIC VDMFUNC PddSetEmul(PUSHORT pIBuff)
{
  Idc_SetEmulation(((PUCHAR)pIBuff)[2]);/* set dddd emul mode                */
  Idc_SetBeep(0);                     /* turn off beeper                     */
  return (TRUE);                      /* ok                                  */
}                                     /* PddSetEmul                          */


/****************************************************************************
 *
 * FUNCTION NAME = PddDisable
 *
 * DESCRIPTION   =
 *   Called from : PddEntry (seg3)
 *   Usage:        Success = PddEntry( 3, NULL, NULL);
 *
 *
 * INPUT         = (VOID)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

STATIC VDMFUNC PddDisable(VOID)
{
  fVdmEnabled = 0;
  return (TRUE);
}                                     /* PddDisable                          */


/****************************************************************************
 *
 * FUNCTION NAME = PddSetExclAcc
 *
 * DESCRIPTION   = Set exclusive access on/off
 *   Called from : PddEntry (seg3)
 *   Usage:        Success = PddEntry( 4, &DataAddr, NULL);
 *
 *
 * INPUT         = (PUSHORT pIBuff)
 *                  Exclusive Access Data:
 *                    USHORT  size = 3
 *                    UCHAR   exclusive access flag (0 - off, 1 - on)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

STATIC VDMFUNC PddSetExclAcc(PUSHORT pIBuff)
{
  PSGCB pShellSgcb;

  if ((pShellSgcb = FindCb(SESN_SHELL)) == NULL)
    return (FALSE);                   /* error                               */

  /* Turn emul off in shell sgcb if exclusive access set & vice versa.       */
  pShellSgcb->EmulState = !(fExclAccess = ((PUCHAR)pIBuff)[2]);

  if (FgndSess == SESN_SHELL)
    Idc_SetEmulation(pFgndSgcb->EmulState);  /* Update DDDD                  */

  return (TRUE);                      /* ok                                  */
}                                     /* PddSetExclAcc                       */


#ifdef   DEBUG

/****************************************************************************
 *
 * FUNCTION NAME = panic
 *
 * DESCRIPTION   =
 *
 *
 * INPUT         = (PSZ file,USHORT line,PSZ fmt,...)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID FAR CDECL panic(PSZ file, USHORT line, PSZ fmt,...)
{
  char msg[128];                      /* size fixed by dh_int_err func above */
  char lnum[16];                      /* array to hold integer "-65536"      */

  itoa(line, lnum, 10);
  _fstrcpy(msg, DDNAME" panic: file ");
  _fstrcat(msg, file);
  _fstrcat(msg, " at line ");
  _fstrcat(msg, lnum);
  _fstrcat(msg, ": ");
  _fstrcat(msg, fmt);
  _fstrcat(msg, "$");                 /* terminator!                         */

  DHInternalError(msg, _fstrlen(msg));
}                                     /* panic                               */

#endif

/*
** end
*/
