/*static char *SCCSID = "@(#)bmsmain.c  6.5 91/10/11";*/

/****************************************************************************/
/*                                                                          */
/*                       IBM/Microsoft Confidential                         */
/*                                                                          */
/*                 Copyright (c) IBM Corporation  1987, 1990                */
/*                 Copyright (c) Microsoft Corp.  1987, 1990                */
/*                           All Rights Reserved                            */
/*                                                                          */
/****************************************************************************/

/*********************** START OF SPECIFICATIONS *****************************/
/*                                                                           */
/* Source File Name: BMSMAIN.C                                               */
/*                                                                           */
/* Descriptive Name: Mouse Subsystem                                         */
/*                                                                           */
/* CopyRight: (c) IBM Corp. 1987, 1991                                       */
/*                                                                           */
/* Status: OS/2 Release 2.00                                                 */
/*                                                                           */
/* Function: This module contains the main entry point for the Base          */
/*           Mouse Subsystem.                                                */
/*                                                                           */
/* Entry Points:                                                             */
/* Internal      BMSMAIN - Main entry for base mouse subsystem               */
/*                                                                           */
/* External References:                                                      */
/* Routines:   DosOpen                                                       */
/*             DosDevIOCtl                                                   */
/*             DosClose                                                      */
/*             DosGetInfoSeg                                                 */
/*             DosReallocSeg                                                 */
/*             DosFSRamSemRequest                                            */
/*             DosFSRamSemClear                                              */
/*             DosFreeSeg                                                    */
/*             DosExitList                                                   */
/*             DosLoadModule                                                 */
/*             DosGetProcAddr                                                */
/*             Refer to extern calls below prolog                            */
/*                                                                           */
/* Data: Refer to Instance and common data declarations below prolog         */
/*                                                                           */
/* Notes:                                                                    */
/*   Dependencies: 0 must be an invalid selector.                            */
/*                 0 must be an invalid current process PID.                 */
/*                                                                           */
/*   Restrictions: This source file must be compiled with the data segment,  */
/*                 BMSCOMN, which is the base mouse subsystem shared data    */
/*                 segment.                                                  */
/*                                                                           */
/*********************** END OF SPECIFICATIONS *******************************/
/*****************************************************************************/
/*******   C H A N G E       H I S T O R Y   *********************************/
/*
 @T52     = 01/19/90  TPL  DCR 704 work
 060982     03/01/93  GDW  Changes for allowing the Bms_Set_Pointer_Draw
                           routine to only open the POINTER$ device driver
                           and moved the call to open MOUSE$ back into
                           BMSOPEN routine.
 072211     08/31/93  GDW  Changed the parm used by DOSSMGETSGCB() located
                           in SGCBInit routine.  Fixes deadlock when a VIO
                           popup is started and MouOpen is called.
 MDLL     = 01/10/94  BJN  PAGE TUNE MERGE DOSCALL1.DLL placing BMSMAIN by
                           itself here and the others procs in BMSMAIN2.C
                           BMSFUNCTIONS is also here from BMSXXX.C
*/
/*****************************************************************************/

/*****************************************************************************/
/*******   Defines for inclusion of required typedefs, etc... ****************/
/*****************************************************************************/
#define INCL_ERRORS
#define INCL_VIO
#define INCL_MOU
#define INCL_DOSSEMAPHORES
#define INCL_DOSPROCESS
#define INCL_DOSINFOSEG
#define INCL_DOSMEMMGR
#define INCL_DOSMODULEMGR
#define INCL_DOSDEVICES

#include <os2.h>
#include <dos.h>
#include <smrsgcb.h>
#include "bmsmain.h"

/*****************************************************************************/
/* External Procedures                                                       */
/*****************************************************************************/
USHORT pascal   SGCBInit(VOID);
USHORT pascal   BmsClose(USHORT, USHORT, PUSHORT*, PUSHORT*);
USHORT pascal   BmsFlushQue(USHORT, USHORT, PUSHORT*, PUSHORT*);
USHORT pascal   BmsFunctions(USHORT, USHORT, PUSHORT*, PUSHORT*);
USHORT pascal   BmsOpen(USHORT, USHORT, PUSHORT*, PUSHORT*);
USHORT pascal   BmsReadEventQue(USHORT, USHORT, PUSHORT*, PUSHORT*);
USHORT pascal   ShldAlwaysGood(USHORT, USHORT, PUSHORT*, PUSHORT*);
USHORT pascal   ShldClose(USHORT, USHORT, PUSHORT*, PUSHORT*);
USHORT pascal   ShldFlushQue(USHORT, USHORT, PUSHORT*, PUSHORT*);
USHORT pascal   ShldGetDevStatus(USHORT, USHORT, PUSHORT*, PUSHORT*);
USHORT pascal   ShldGetEventMask(USHORT, USHORT, PUSHORT*, PUSHORT*);
USHORT pascal   ShldGetNumQueEl(USHORT, USHORT, PUSHORT*, PUSHORT*);
USHORT pascal   ShldGetNumButt(USHORT, USHORT, PUSHORT*, PUSHORT*);
USHORT pascal   ShldGetNumMick(USHORT, USHORT, PUSHORT*, PUSHORT*);
USHORT pascal   ShldGetPtrPos(USHORT, USHORT, PUSHORT*, PUSHORT*);
USHORT pascal   ShldGetScaleFact(USHORT, USHORT, PUSHORT*, PUSHORT*);
USHORT pascal   ShldGetSetPtrShape(USHORT, USHORT, PUSHORT*, PUSHORT*);
USHORT pascal   ShldGetSetThreshold(USHORT, USHORT, PUSHORT*, PUSHORT*);
USHORT pascal   BmsGetSetThreshold(USHORT, USHORT, PUSHORT*, PUSHORT*);
USHORT pascal   ShldSetDevStatus(USHORT, USHORT, PUSHORT*, PUSHORT*);
USHORT pascal   ShldSetEventMask(USHORT, USHORT, PUSHORT*, PUSHORT*);
USHORT pascal   ShldSetPtrPos(USHORT, USHORT, PUSHORT*, PUSHORT*);
VOID   APIENTRY VioQueryConsole(USHORT far *);

/*****************************************************************************/
/* Shared Data Definitions                                                   */
/*****************************************************************************/
USHORT InitFlag = 0;                          /* Mouse Version retreived = 1 */
                                              /* PMVIOP module loaded    = 4 */
                                              /* BVSMAIN module loaded   = 2 */
                                              /* BMSMAIN module loaded   = 8 */
                                              /* BKSMAIN module loaded   =16 */
PLINFOSEG bms_localinfo = NULL;               /* Local information selector  */
CHAR      MouseFileName[] = "\\DEV\\MOUSE$ "; /* Mouse device name           */
USHORT    MouseVer = 0;                       /* Mouse DD version number     */
CHAR      SkeletonPtrName[]="\\DEV\\       "; /* Skeleton pointer draw name  */
USHORT    NumButtons = 0;                     /* Number of buttons on mouse  */
USHORT    NumMickeys = 0;                     /* Number of mickeys for mouse */

/*****************************************************************************/
/* Winthorn Dynamic link module entry points and module names.               */
/* The code is table driven and therefore care should be taken in            */
/* rearranging this table. The table is set up so that if an error occurs    */
/* during DosGetProcAddr that it can resume where it left off on the next    */
/* MOUXXXX call.                                                             */
/*****************************************************************************/
CHAR   Shield_DLL[] = "PMVIOP";                        /* Name of SHIELD.DLL */
USHORT ShieldHandle = 0;                              /* SHIELD module handle*/

USHORT (APIENTRY *WINCONSOLEFLUSHPOINTEREVENTS)()   = 0L; /* Shield address  */
USHORT (APIENTRY *WINCONSOLEQUEUEDPOINTEREVENTS)()  = 0L; /*   "        "    */
USHORT (APIENTRY *WINCONSOLEREADPOINTEREVENT)()     = 0L; /*   "        "    */
USHORT (APIENTRY *WINCONSOLEGETPOINTERFILTERMASK)() = 0L; /*   "        "    */
USHORT (APIENTRY *WINCONSOLESETPOINTERFILTERMASK)() = 0L; /*   "        "    */
USHORT (APIENTRY *WINCONSOLEGETPTRPOS)()            = 0L; /*   "        "    */
USHORT (APIENTRY *WINCONSOLESETPTRPOS)()            = 0L; /*   "        "    */
USHORT (APIENTRY *WINCONSOLEATTACHMOUSEUSER)()      = 0L; /*   "        "    */
USHORT (APIENTRY *WINCONSOLEDETACHMOUSEUSER)()      = 0L; /*   "        "    */
USHORT ShieldEntries = 9;                        /* Number of Shield Entries */
ULONG  Shield_33 = 33L;                   /* WINCONSOLEDETACHMOUSEUSER       */
ULONG  Shield_32 = 32L;                   /* WINCONSOLEATTACHMOUSEUSER       */
ULONG  Shield_23 = 23L;                   /* WINCONSOLESETPTRPOS             */
ULONG  Shield_22 = 22L;                   /* WINCONSOLEGETPTRPOS             */
ULONG  Shield_21 = 21L;                   /* WINCONSOLESETPOINTERFILTERMASK  */
ULONG  Shield_20 = 20L;                   /* WINCONSOLEGETPOINTERFILTERMASK  */
ULONG  Shield_18 = 18L;                   /* WINCONSOLEREADPOINTEREVENT      */
ULONG  Shield_17 = 17L;                   /* WINCONSOLEQUEUEDPOINTEREVENTS   */
ULONG  Shield_19 = 19L;                   /* WINCONSOLEFLUSHPOINTEREVENTS    */

/*****************************************************************************/
/* The following function table directs each MOUXXXX function to the         */
/* appropriate worker routine based on the function number on the stack.     */
/* The first N functions are for full screen sessions and the next N         */
/* entries are for windowed VIO sessions.                                    */
/*****************************************************************************/

USHORT (near pascal *FunctionTable[44])(USHORT,USHORT,PUSHORT*,PUSHORT*)={
                                   BmsFunctions,     /* Get # buttons        */
                                   BmsFunctions,     /* Get # mickeys        */
                                   BmsFunctions,     /* Get device status    */
                                   BmsFunctions,     /* Get # queue elem.    */
                                   BmsReadEventQue,  /* Read event queue     */
                                   BmsFunctions,     /* Get scale factor     */
                                   BmsFunctions,     /* Get event mask       */
                                   BmsFunctions,     /* Set scale factor     */
                                   BmsFunctions,     /* Set event mask       */
                                   BmsGetSetThreshold,/* Get threshold       */
                                   BmsGetSetThreshold,/* Set threshold       */
                                   BmsOpen,          /* Open                 */
                                   BmsClose,         /* Close                */
                                   BmsFunctions,     /* Get pointer shape    */
                                   BmsFunctions,     /* Set pointer shape    */
                                   BmsFunctions,     /* Draw pointer         */
                                   BmsFunctions,     /* Remove pointer       */
                                   BmsFunctions,     /* Get pointer pos.     */
                                   BmsFunctions,     /* Set pointer pos.     */
                                   BmsFunctions,     /* RESERVED             */
                                   BmsFlushQue,      /* Flush queue          */
                                   BmsFunctions,     /* Set device status    */

/* Windowed VIO SG calls */

                                   ShldGetNumButt,   /* Get # buttons        */
                                   ShldGetNumMick,   /* Get # mickeys        */
                                   ShldGetDevStatus, /* Get device status    */
                                   ShldGetNumQueEl,  /* Get # queue elem.    */
                                   BmsReadEventQue,  /* Read event queue     */
                                   ShldGetScaleFact, /* Get scale factor     */
                                   ShldGetEventMask, /* Get event mask       */
                                   ShldAlwaysGood,   /* Set scale factor     */
                                   ShldSetEventMask, /* Set event mask       */
                                   ShldGetSetThreshold,/* Get threshold      */
                                   ShldGetSetThreshold,/* Set threshold      */
                                   BmsOpen,          /* Open                 */
                                   ShldClose,        /* Close                */
                                   ShldGetSetPtrShape,/* Get pointer shape   */
                                   ShldGetSetPtrShape,/* Set pointer shape   */
                                   ShldAlwaysGood,   /* Draw pointer         */
                                   ShldAlwaysGood,   /* Remove pointer       */
                                   ShldGetPtrPos,    /* Get pointer pos.     */
                                   ShldSetPtrPos,    /* Set pointer pos.     */
                                   ShldAlwaysGood,   /* RESERVED  InitReal   */
                                   ShldFlushQue,     /* Flush queue          */
                                   ShldAlwaysGood};  /* Set device status    */

/*****************************************************************************/
/* The generic worker, BmsFunctions, uses the function number to retrieve    */
/* the IOCTL number to use when calling DOSDEVIOCTL from the following table.*/
/*****************************************************************************/

BYTE IoctlTable[22] = {0x60,     /* Get # of mouse buttons                   */
                       0x61,     /* Get # of mickeys/centimeter              */
                       0x62,     /* Get device status flags                  */
                       0x64,     /* Get # of event queue element(s)          */
                       0x63,     /* Read event queue contents                */
                       0x66,     /* Get current scaling factors              */
                       0x65,     /* Get current event mask                   */
                       0x53,     /* Set new scaling factors                  */
                       0x54,     /* Set new event mask                       */
                       0x69,     /* Get threshold info                       */
                       0x55,     /* Set threshold info                       */
                       0x0,      /* Open place holder - not used             */
                       0x0,      /* Close place holder - not used            */
                       0x68,     /* Get pointer shape image                  */
                       0x56,     /* Set new pointer shape                    */
                       0x57,     /* Draw pointer - unmarked collision area   */
                       0x58,     /* Remove pointer - mark collision area     */
                       0x67,     /* Get pointer screen position              */
                       0x59,     /* Set pointer position                     */
                       0x5B,     /* Set real mode pointer draw routine addr. */
                       0x0,      /* Flush Queue place holder - not used      */
                       0x5C};    /* Set device status flags                  */

/*****************************************************************************/
/* The function number is used to index into this table. Each byte is a      */
/* bit mask which tells BMSMAIN how to interpret and send the user           */
/* parameters to the generic workers.                                        */
/*      00 = Worker does not require parameters                              */
/*      10 = parm1ptr is the first user parameter, parm1of2                  */
/*      01 = parm2ptr is set to the first user parameter, parm1of2           */
/*      02 = parm2ptr is set to the second user parameter, parm1of3          */
/*****************************************************************************/

BYTE ParmTable[22] = {0x10,      /* Get # of mouse buttons                   */
                      0x10,      /* Get # of mickeys/centimeter              */
                      0x10,      /* Get device status flags                  */
                      0x10,      /* Get # of event queue element(s)          */
                      0x12,      /* Read event queue contents                */
                      0x10,      /* Get current scaling factors              */
                      0x10,      /* Get current event mask                   */
                      0x01,      /* Set new scaling factors                  */
                      0x01,      /* Set new event mask                       */
                      0x10,      /* Get threshold info                       */
                      0x01,      /* Set threshold info                       */
                      0,         /* Open place holder - not used             */
                      0,         /* Close place holder - not used            */
                      0x12,      /* Get pointer shape image                  */
                      0x12,      /* Set new pointer shape                    */
                      0,         /* Draw pointer - unmarked collision area   */
                      0x01,      /* Remove pointer - mark collision area     */
                      0x10,      /* Get pointer screen position              */
                      0x01,      /* Set pointer position                     */
                      0,         /* RESERVED InitReal                        */
                      0,         /* Flush Queue place holder - not used      */
                      0x01};     /* Set device status flags                  */
CHAR   end_CDATA = 0;            /* end of global data                   @T52*/



/*********************** START OF SPECIFICATIONS *****************************/
/*                                                                           */
/* DESCRIPTIVE NAME:  Base Mouse Subsystem Main Entry                   MDLL */
/*                                                                      MDLL */
/* FUNCTION:  Provides functional support for the OS/2 MOUXXXX calls.   MDLL */
/*                                                                      MDLL */
/* NOTES:                                                               MDLL */
/*                                                                      MDLL */
/* ENTRY POINT:  BMSMAIN                                                MDLL */
/*   LINKAGE:  CALL FAR                                                 MDLL */
/*                                                                      MDLL */
/* INPUT:  Stack Frame                                                  MDLL */
/*   SP at ---> mouroutip       WORD    MOUROUT return offset           MDLL */
/*   Entry      mouroutcs       WORD    MOUROUT return selector         MDLL */
/*              mouroutds       WORD    MOUROUT data selector           MDLL */
/*              mouip           WORD    MOUxxx return offset            MDLL */
/*              moufunc         WORD    MOUxxx Function code            MDLL */
/*              userip          WORD    User return offset              MDLL */
/*              usercs          WORD    User return segment             MDLL */
/*              parmn           WORD    Nth parameter                   MDLL */
/*              parmnm1         WORD    (N-1)st parameter               MDLL */
/*              parmnm2         WORD    (N-2)nd parameter               MDLL */
/*              parmnm3         WORD    (N-3)rd parameter               MDLL */
/*              parmnm4         WORD    (N-4)th parameter               MDLL */
/*              parmnm5         WORD    (N-5)th parameter               MDLL */
/*              parmnm6         WORD    (N-6)th parameter               MDLL */
/*              parmnm7         WORD    (N-7)th parameter               MDLL */
/*              parmnm8         WORD    (N-8)th parameter               MDLL */
/*              parmnm9         WORD    (N-9)th parameter               MDLL */
/*                                                                      MDLL */
/*   Where moufunc = 00h, MouGetNumButtons      0Bh, MouOpen            MDLL */
/*                   01h, MouGetNumMickeys      0Ch, MouClose           MDLL */
/*                   02h, MouGetDevStatus       0Dh, MouGetPtrShape     MDLL */
/*                   03h, MouGetNumQueEl        0Eh, MouSetPtrShape     MDLL */
/*                   04h, MouReadEventQue       0Fh, MouDrawPtr         MDLL */
/*                   05h, MouGetScaleFact       10h, MouRemovePtr       MDLL */
/*                   06h, MouGetEventMask       11h, MouGetPtrPos       MDLL */
/*                   07h, MouSetScaleFact       12h, MouSetPtrPos       MDLL */
/*                   08h, MouSetEventMask       13h, RESERVED           MDLL */
/*                   09h, MouGetThreshold       14h, MouFlushQue        MDLL */
/*                   0Ah, MouSetThreshold       15h, MouSetDevStatus    MDLL */
/*                                              18h, MouFree            MDLL */
/*                                                                      MDLL */
/* EXIT-NORMAL:  AX = 0                                                 MDLL */
/*                                                                      MDLL */
/* EXIT-ERROR: AX = ERROR_MOU_NOT_INITIALIZED                           MDLL */
/*                  ERROR_MOUSE_NO_CONSOLE                              MDLL */
/*                  ERROR_MOUSE_INVALID_HANDLE                          MDLL */
/*                  Error code from DosOpen                             MDLL */
/*                  Error code from DosLoadModule                       MDLL */
/*                  Error code from DosGetProcAddr                      MDLL */
/*                  Error code from DosExitList                         MDLL */
/*                  Error code from DosFSRamSemRequest                  MDLL */
/*                                                                      MDLL */
/* SIDE EFFECTS:  None                                                  MDLL */
/*                                                                      MDLL */
/************************ END OF SPECIFICATIONS ******************************/

USHORT APIENTRY _loadds _saveregs BMSMAIN()
{
   USHORT             Handle;           /* Handle to pass to worker          */
   USHORT             MouFunc;          /* Mouse function requested          */
   USHORT             CallBase;         /* Set to 22 if windowed session     */
   USHORT             RC;               /* Return code                       */
   USHORT             ParmFlags;        /* Temporary variable for bit mask   */
   PUSHORT            *parm1ptr;        /* Address to first worker parameter */
   PUSHORT            *parm2ptr;        /* Address to second worker parameter*/
   PSZ far            *ShieldNames;     /* Address to shield ordinal         */
   PFN far            *ShieldAddr;      /* Address to store procedure addr   */
   struct STACKFRAME far  *stackptr;    /* Assuming this is at BP-4 WARNING! */

   /**************************************************************************/
   /* Don't refer to local variables before this statement. This includes    */
   /* initialization on the internal declarations.  This statement sets the  */
   /* stackptr to point to the first local variable on stack, (BP-4).        */
   /**************************************************************************/
   stackptr = (struct STACKFRAME far *)&ShieldAddr;       /* Must be a BP-4  */

   RC = NO_ERROR;
   CallBase = 0;
   parm1ptr = 0L;
   parm2ptr = 0L;
   MouFunc = stackptr->FunctionNum;            /* MOU API being called       */
   Handle = stackptr->DeviceHandle;            /* Application's mouse handle */

   /**********************************************************/
   /* If process changed Screen Group ID to SG #3, (Popup),  */
   /* Call SGCBInit() to get screen group control block      */
   /* information for current Screen Group.                  */
   /**********************************************************/
   if(bms_localinfo->sgCurrent != currSG)
     RC = SGCBInit();

   if ((MouFunc == MOUOPEN) || (MouFunc == MOUCLOSE))
     {

       /********************************************/
       /* Internally synchronize the open, close,  */
       /********************************************/
       do
         {
           RC = DosFSRamSemRequest(
                        (PDOSFSRSEM)&(sgdata_el->BMS_OpenCloseFSSem.cb),
                                                   SEM_INDEFINITE_WAIT);
         }
       while (RC == ERROR_INTERRUPT);
       parm1ptr = (PUSHORT far *)stackptr;
     }
   if (RC == NO_ERROR)
     {

       /**********************************************************************/
       /* For windowed text screen groups, establish the base offset to use  */
       /* in conjunction with the requested function code to get the proper  */
       /* index in the function table                                        */
       /**********************************************************************/
       if (currTYPE == PT_WINDOWABLEVIO)              /* Text Window SG Type */
         {
           CallBase = 22;      /* Set base for Window calls in FunctionTable */

           /************************************************/
           /* Load the PM shield dynamic link library ONCE */
           /************************************************/
           if ((InitFlag & LOADMODULEDONE) == FALSE)
             {
               RC = DosLoadModule(0L, 0, (CHAR far *)Shield_DLL,
                                               (USHORT far*)&ShieldHandle);
               if (RC == NO_ERROR)
                 {
                   /**********************************************************/
                   /* The procedure addresses are only loaded once for all   */
                   /* processes through DosGetProcAddr. The data is organized*/
                   /* so that if an error occurs in the middle of getting the*/
                   /* procedure addresses the next attempt will pick up where*/
                   /* it was when the error occurred. This cannot be moved to*/
                   /* the Per Process initialization routine because the     */
                   /* system cannot handle an error condition returned by a  */
                   /* module loaded by DosLoadModule() when that module has  */
                   /* its own initialization routine.                        */
                   /**********************************************************/

                   if (ShieldEntries > 0)
                     {
                       ShieldNames = (PSZ far *)&ShieldEntries;
                       ShieldAddr = (PFN far *)&ShieldEntries;
                       ParmFlags = ShieldEntries << 2; /* Shield Entries * 4 */
                       ShieldAddr = MAKEP(FP_SEG(ShieldAddr),
                                              FP_OFF(ShieldAddr)-ParmFlags);
                       ShieldNames = MAKEP(FP_SEG(ShieldNames),
                                              FP_OFF(ShieldNames)+ParmFlags-2);

                       for (; ((ShieldEntries > 0) && (RC == NO_ERROR));
                                ShieldEntries--,ShieldAddr++,ShieldNames--)
                         {
                           RC = DosGetProcAddr(ShieldHandle,*ShieldNames,
                                                                 ShieldAddr);
                         }
                     }
                 }
               if (RC != NO_ERROR)
                 RC = ERROR_MOUSE_NO_CONSOLE;
               else
                 InitFlag |= LOADMODULEDONE;
             }
           if (RC == NO_ERROR)
             {
              /***************************************************************/
              /* Get the console handle for the current text windowed session*/
              /***************************************************************/
               if (hConsole == 0)
                 {
                   VioQueryConsole(&hConsole);
                   if (hConsole == 0)
                     RC = ERROR_MOUSE_NO_CONSOLE;
                 }
               if (RC == NO_ERROR)
                 {
                   /*********************************************************/
                   /* If the mouse is not opened, it is an error unless an  */
                   /* Open is being processed.                              */
                   /*********************************************************/
                   if ((MouFunc != MOUOPEN) &&
                       ((Handle != hConsole) || (MouOpenCnt == 0)))
                     {
                       RC = ERROR_MOUSE_INVALID_HANDLE;
                     }
                 }
             }
           /*************************************************************/
           /* Get the handle to the mouse device driver since the user  */
           /* specified handle is the Console handle for windowed text  */
           /* sessions and will also be used in BMSXXX.C to call the    */
           /* PM shield layer.                                          */
           /*************************************************************/
           Handle = WTMouseHandle;

         }

       /********************************************************************/
       /* Use the specified function code to obtain the parameter bit mask */
       /********************************************************************/
       if (RC == NO_ERROR)
         {
           ParmFlags = ParmTable[MouFunc];

           /***********************************************/
           /* If the bit mask is 0, parm1ptr and parm2ptr */
           /* are NULL or already set                     */
           /***********************************************/
           if (ParmFlags)
             {

               /*****************************************************/
               /* parm1ptr equals the first user specified address  */
               /*****************************************************/
               if (ParmFlags & 0x10)
                 parm1ptr = stackptr->Parm1of2;

               /****************************************************/
               /* parm2ptr equals the first user specified address */
               /****************************************************/
               if (ParmFlags & 0x01)
                 parm2ptr = stackptr->Parm1of2;
               else
                 /*****************************************************/
                 /* parm2ptr equals the second user specified address */
                 /*****************************************************/
                 if (ParmFlags & 0x02)
                   parm2ptr = stackptr->Parm1of3;
             }

           /*****************************************************************/
           /* Use the function code and CallBase index to make an indirect  */
           /* call to a worker procedure for the requested mouse function   */
           /*****************************************************************/
           RC = FunctionTable[(MouFunc+CallBase)](MouFunc,Handle,parm1ptr,
                                                                 parm2ptr);
         }
     }

   /**************************************************************************/
   /* Clear the Open/Close synchronization semaphore. If this thread doesn't */
   /* own the semaphore, it is assumed an error will be returned and the     */
   /* semaphore will not be cleared                                          */
   /**************************************************************************/
   DosFSRamSemClear((PDOSFSRSEM)&(sgdata_el->BMS_OpenCloseFSSem));
   return(RC);

} /* END BMSMAIN Routine */

/*********************** START OF SPECIFICATIONS *****************************/
/*                                                                      MDLL */
/* SUBROUTINE NAME: BmsFunctions                                        MDLL */
/*                                                                      MDLL */
/* DESCRIPTIVE NAME: Generic base mouse subsystem worker                MDLL */
/*                                                                           */
/* FUNCTION: Processes all base mouse subsystem calls that are simply passed */
/*           through the subsystem to the mouse device driver.               */
/*                                                                           */
/* NOTES: The ParmTable specified in BMSMAIN contains the bit mask which     */
/*        indicates how to set up parm1ptr and parm2ptr for each mouse       */
/*        function that calls BmsFunctions.                                  */
/*                                                                           */
/*        The mouse function code is used to index into a table that         */
/*        contains the appropriate IOCTL number for each mouse function.     */
/*                                                                           */
/* ENTRY POINT: BmsFunctions                                                 */
/*     LINKAGE: CALL NEAR                                                    */
/*                                                                           */
/* INPUT: Handle - Mouse device driver handle returned by MOUOPEN            */
/*        parm1ptr - usually the first user specified input address for      */
/*                   get functions and 0 for set functions                   */
/*        parm2ptr - usually the first user specified input address for      */
/*                   set functions and 0 for get functions                   */
/*                                                                           */
/* EXIT-NORMAL: AX = NO_ERROR                                                */
/*                                                                           */
/* EXIT-ERROR: AX = Error code from DosDevIOCtl                              */
/*                                                                           */
/* SIDE EFFECTS:                                                             */
/*                                                                           */
/*********************** END OF SPECIFICATIONS *******************************/
/* BmsFunctions(Function,Handle,parm1ptr,parm2ptr)        */

USHORT pascal BmsFunctions(Function,Handle,parm1ptr,parm2ptr)
USHORT Function;                        /* Mouse function requested          */
USHORT Handle;                          /* Mouse device driver handle        */
PUSHORT *parm1ptr;                      /* 1st user parameter for most gets  */
PUSHORT *parm2ptr;                      /* 1st user parameter for most sets  */
{

   return(DosDevIOCtl((PVOID)parm1ptr,(PVOID)parm2ptr,
                      IoctlTable[Function], MOUSECONTROL,Handle));

}  /* END BMSFUNCTIONS Routine */
