/*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: BMSMAIN2.C                                              */
/*                                                                           */
/* Descriptive Name: Mouse Subsystem                                         */
/*                                                                           */
/* CopyRight: (c) IBM Corp. 1987, 1991                                       */
/*                                                                           */
/* Status: OS/2 Release 2.00                                                 */
/*                                                                           */
/* Function: This module contains several common procedures, process         */
/*           initialization, exitlist.                                       */
/*                                                                           */
/* Entry Points:                                                             */
/* Internal      MouseOpen - Open \DEV\MOUSE$ device driver                  */
/*               BMSINIT - Base mouse subsystem process initialization       */
/*               BMSEXITLIST - Base mouse subsystem exit list procedure      */
/* Internal      Bms_Set_Pointer_Draw - Get/set pointer draw entry and DS    */
/*                                                                           */
/* 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
 AB00112  = 08/05/91  GDW  The far address sent to DosSMFreeMem() was incorrect
                           causing a TRAP D, (Address of address instead of
                           address).
 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.
*/
/*****************************************************************************/

/*****************************************************************************/
/*******   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"

int _cdecl far strnicmp(char far *, char far *, USHORT);
char * _cdecl far strncpy(char far *, char far *, USHORT);

USHORT pascal   MouseOpen(USHORT far *);

/*****************************************************************************/
/* External Procedures                                                       */
/*****************************************************************************/
USHORT APIENTRY DOSSMGETMEM(PSGCB,USHORT);
USHORT APIENTRY DOSSMFREEMEM(PSGCB);
USHORT APIENTRY DOSSMGETSGCB(PSGCB,USHORT,USHORT);

/*****************************************************************************/
/* Shared Data Definitions                                                   */
/*****************************************************************************/
extern   USHORT    InitFlag;                  /* Mouse Version retreived = 1 */
                                              /* Load Module completed = 2   */
extern   PLINFOSEG bms_localinfo;             /* Local information selector  */
extern   CHAR      MouseFileName[];           /* Mouse device name           */
extern   USHORT    MouseVer;                  /* Mouse DD version number     */
extern   CHAR      SkeletonPtrName[];         /* Skeleton pointer draw name  */
extern   USHORT    NumButtons;                /* Number of buttons on mouse  */
extern   USHORT    NumMickeys;                /* Number of mickeys for mouse */

/*********************** START OF SPECIFICATIONS *****************************/
/*                                                                           */
/* SUBROUTINE NAME: MouseOpen                                                */
/*                                                                           */
/* DESCRIPTIVE NAME: Open mouse                                              */
/*                                                                           */
/* FUNCTION: Open the \DEV\MOUSE$ device driver.                             */
/*                                                                           */
/* NOTES:                                                                    */
/*                                                                           */
/* ENTRY POINT: MouseOpen                                                    */
/*     LINKAGE: CALL NEAR                                                    */
/*                                                                           */
/* INPUT: Handle - address to return mouse handle                            */
/*                                                                           */
/* EXIT-NORMAL: AX = NO_ERROR                                                */
/*                                                                           */
/* EXIT-ERROR: AX = Error code from DosOpen                                  */
/*                                                                           */
/* SIDE EFFECTS:                                                             */
/*                                                                           */
/*********************** END OF SPECIFICATIONS *******************************/
/* MouseOpen(Handle)                                                         */

USHORT pascal MouseOpen(Handle)
USHORT far * Handle;                    /* Address to return mouse handle    */
{
   USHORT  ActionTaken;                 /* Action taken if MOUSE$ doesn't    */
                                        /* exist                             */

   return(DosOpen(MouseFileName,Handle,&ActionTaken,0L,0,1,0xC2,0L));

}

/*********************** START OF SPECIFICATIONS *****************************/
/*                                                                           */
/* SUBROUTINE NAME: GlobalInit                                               */
/*                                                                           */
/* DESCRIPTIVE NAME: Global (one time) initialization routine.               */
/*                                                                           */
/* FUNCTION: Open mouse to retrieve the Mouse version number, get the number */
/*           of buttons and the number of mickeys for the installed mouse.   */
/*                                                                           */
/* NOTES:                                                                    */
/*                                                                           */
/* ENTRY POINT: GlobalInit                                                   */
/*     LINKAGE: CALL NEAR                                                    */
/*                                                                           */
/* INPUT: NA                                                                 */
/*                                                                           */
/* EXIT-NORMAL: AX = NO_ERROR                                                */
/*                                                                           */
/* EXIT-ERROR: AX = Error code from MouseOpen                                */
/*                                                                           */
/* SIDE EFFECTS:  InitFlag is OR'd with 1 to indicate completion.            */
/*                                                                           */
/*********************** END OF SPECIFICATIONS *******************************/
/* GlobalInit()                                                              */

USHORT pascal GlobalInit()

{
  USHORT  TempHandle;                  /* Temporary mouse Open Handle       */
  USHORT  RC = NO_ERROR;

  /********************************************/
  /* Attempt to open the mouse device driver  */
  /********************************************/
  RC = MouseOpen((USHORT far *)&TempHandle);
  if (RC == NO_ERROR)
    {
      /***************************************/
      /* Obtain the mouse version number and */
      /* close the mouse device driver.      */
      /***************************************/
      RC = DosDevIOCtl(&MouseVer,0L, VERSION, MOUSECONTROL, TempHandle);
      if (RC == NO_ERROR)
        {
          /*********************************************/
          /* Obtain number of buttons on mouse device. */
          /*********************************************/
          RC = DosDevIOCtl(&NumButtons,0L, BUTTONS, MOUSECONTROL, TempHandle);
          if (RC == NO_ERROR)
            /**********************************************/
            /* Obtain number of mickeys for mouse device. */
            /**********************************************/
            RC = DosDevIOCtl(&NumMickeys,0L, MICKEYS, MOUSECONTROL, TempHandle);
        }
      DosClose(TempHandle);
      if (RC == NO_ERROR)
        InitFlag |= INITDONE;
    }
  return(RC);

} /* END GlobalInit */

/*********************** START OF SPECIFICATIONS *****************************/
/*                                                                           */
/* SUBROUTINE NAME: SGCBInit                                                 */
/*                                                                           */
/* DESCRIPTIVE NAME: Screen Group Control Block initializaton routine.       */
/*                                                                           */
/* FUNCTION: Get access to the Screen Group Control Block owned by the       */
/*           Session Manager and initialize the work area for the BMS.       */
/*                                                                           */
/* NOTES:                                                                    */
/*                                                                           */
/* ENTRY POINT: SGCBInit                                                     */
/*     LINKAGE: CALL NEAR                                                    */
/*                                                                           */
/* INPUT: NA                                                                 */
/*                                                                           */
/* INTERNAL REFERENCES:                                                      */
/*                                                                           */
/*        ROUTINES: DosGetInfoSeg - Retreives the address of the Global and  */
/*                                  local information segments.              */
/*                  DOSSMGETSGCB  - Retreives the address of the screen      */
/*                                  group control block.                     */
/*                  DOSSMGETMEM   - Retreives a memory block from the        */
/*                                  Session Manager and assigns the address  */
/*                                  to a field accessed in the SGCB.         */
/*                  DosOpen       - Opens the Mouse for DosDevIoctl calls    */
/*                  DosDevIoctl   - Used to initialize pointer shape and     */
/*                                  threshold values used in Text Windows    */
/*                  DosClose      - Closes the mouse                         */
/*                  DOSSMFREEMEM  - Free's allocated memory if an error      */
/*                                  condition occurs.                        */
/* EXIT-NORMAL: AX = NO_ERROR                                                */
/*                                                                           */
/* EXIT-ERROR: AX = Error code from DosOpen                                  */
/*                                                                           */
/* SIDE EFFECTS:  currSG is assigned the current Screen Group ID             */
/*                currPID is assigned the current Screen Group PID           */
/*                currTYPE is assigned the current Screen Group TYPE         */
/*                sgdata_el is assigned the address of Session Managers SGCB */
/*                                                                           */
/*********************** END OF SPECIFICATIONS *******************************/
/* SGCBInit()                                                                */

USHORT pascal SGCBInit()

{
  SEL     local_sel;                    /* Local information selector        */
  SEL     global_sel;                   /* Global information selector       */
  USHORT  TempHandle;                   /* Temporary mouse Open Handle       */
  USHORT  RC = NO_ERROR;

  /*********************************************/
  /* get the infosegs for the calling process  */
  /*********************************************/
  DosGetInfoSeg(&global_sel, &local_sel);
  bms_localinfo = MAKEP(local_sel,0);

  /*******************************************/
  /* Assign the address of the current       */
  /* Screen Group Control Block to sgdata_el */
  /*******************************************/
  RC = DOSSMGETSGCB((struct SGCB far *)&sgdata_el,
                                        bms_localinfo->sgCurrent, /* 72211 */
                                        0);

  if ((RC == NO_ERROR) && (!sgdata_el->BMS_InitFlag))
    {
      if (currTYPE == PT_WINDOWABLEVIO)
        {
          RC = DOSSMGETMEM((PSGCB)&(sgdata_el->BMS_TextCB),TextCBSize);
          if (RC == NO_ERROR)
            {
              sgdata_el->BMS_TextCB->PtrDefRec[0] = 4;/* Shape Len set */
              sgdata_el->BMS_TextCB->Threshold[0] = 10;/* Thresh Len set*/
              RC = MouseOpen((USHORT far *)&TempHandle);

              if (RC == NO_ERROR)
                {
                  /*****************************************************/
                  /* Defaults for Shape set for Windowed Screen Groups */
                  /*****************************************************/
                  RC = DosDevIOCtl((PVOID)sgdata_el->BMS_TextCB->PtrDefRec,
                                   (PVOID)sgdata_el->BMS_TextCB->PtrBuffer,
                                          GETSHAPE,
                                          MOUSECONTROL,
                                          TempHandle);

                  if (RC == NO_ERROR)
                    {
               /*********************************************************/
               /* Defaults for Threshold set for Windowed Screen Groups */
               /*********************************************************/
                      RC = DosDevIOCtl((PVOID)sgdata_el->BMS_TextCB->Threshold,
                                       (PVOID)global_sel,
                                              GETTHRESH,
                                              MOUSECONTROL,
                                              TempHandle);
                      if (RC == NO_ERROR)
                        {
                          sgdata_el->BMS_OpenCloseFSSem.cb = 14;
                          sgdata_el->BMS_InitFlag |= INITDONE;
                        }
                    }
                  DosClose(TempHandle);
                }
              if (RC != NO_ERROR)
              {                                                                 /* @DB64432 */
                DOSSMFREEMEM((PSGCB)(sgdata_el->BMS_TextCB));     /* AB00112 */
                /*
                 * @DB64432: We MUST clear out the pointer here to inform
                 *           session manager that the memory has already
                 *           been freed, so he doesn't try to free it again.
                 */
                sgdata_el->BMS_TextCB = NULL;                                   /* @DB64432 */
              }                                                                 /* @DB64432 */
            }
        }
      sgdata_el->BMS_OpenCloseFSSem.cb = 14;
      sgdata_el->BMS_InitFlag |= INITDONE;
    }

  return(RC);

} /* END SGCBInit */

/*****************************************************************************/
/*                                                                           */
/* SUBROUTINE NAME:   BMSEXITLIST                                            */
/*                                                                           */
/* DESCRIPTIVE NAME:  Base mouse subsystem exit list procedure               */
/*                                                                           */
/* FUNCTION:   Ensure that the terminating process has released the base     */
/*             mouse subsystem screen group semaphore.                       */
/*                                                                           */
/* NOTES:                                                                    */
/*                                                                           */
/* ENTRY POINTS: BMSEXITLIST()                                               */
/*   LINKAGE: CALL FAR                                                       */
/*                                                                           */
/* INPUT:  None                                                              */
/*                                                                           */
/* EXIT-NORMAL:  None                                                        */
/*                                                                           */
/* EXIT-ERROR:  None                                                         */
/*                                                                           */
/* SIDE EFFECTS:                                                             */
/*                                                                           */
/*****************************************************************************/
/* BMSEXITLIST()                                                             */

void APIENTRY _loadds BMSEXITLIST()
{
   USHORT i;                            /* Loop counter, semaphore own count*/
   USHORT RC;                           /* Return code                      */

   if (bms_localinfo->typeProcess != PT_PM)                  /* PTR 710420  */
     {
       /**********************************************************************/
       /* Did this process establish the pointer draw for this screen group? */
       /**********************************************************************/
       if (sgdata_el->BMS_OwnerPID == currPID)
         sgdata_el->BMS_OwnerPID = 0;       /* Allow another process to set  */
                                            /* a pointer draw device driver  */
       /************************************************************/
       /* Was the process in the middle of an Open or Close call?  */
       /************************************************************/
       if (sgdata_el->BMS_OpenCloseFSSem.pid == currPID)
         {
          /**********************************************************/
          /* Request the semaphore to set the request count to one? */
          /**********************************************************/
          do
            {
            RC=DosFSRamSemRequest((PDOSFSRSEM) &(sgdata_el->BMS_OpenCloseFSSem),
                                                      SEM_IMMEDIATE_RETURN);
            }
          while (RC == ERROR_INTERRUPT);

          /**************************************************/
          /* Clear the Open/Close synchronization semaphore */
          /**************************************************/
          i = sgdata_el->BMS_OpenCloseFSSem.cUsage;
          for (;i > 0; i--)
            {
            RC=DosFSRamSemClear((PDOSFSRSEM) &(sgdata_el->BMS_OpenCloseFSSem));
            if (RC == ERROR_INTERRUPT)
              i++;
            }
         }
     }
   /******************************************/
   /* Proceed to the next exitlist procedure */
   /******************************************/
   DosExitList(EXLST_EXIT, NULL);

}  /* END BMSEXITLIST Routine */

/*****************************************************************************/
/*                                                                           */
/* SUBROUTINE NAME:   BmsInit                                                */
/*                                                                           */
/* DESCRIPTIVE NAME:  Base mouse subsystem initialization                    */
/*                                                                           */
/* FUNCTION:   The base mouse subsystem initialization will call the         */
/*             Global and per process routines when needed. The GlobalInit() */
/*             routine will be called only once.  The SGCBInit() routine     */
/*             will be called at the beginning of each new process. The      */
/*             DosExitList() routine will be called at the beginning of each */
/*             new process to add that process ID for cleanup after the      */
/*             dies.                                                         */
/*                                                                           */
/* NOTES:                                                                    */
/*                                                                           */
/* ENTRY POINTS: BmsInit                                                     */
/*   LINKAGE: CALL FAR                                                       */
/*                                                                           */
/* INPUT:  None                                                              */
/*                                                                           */
/* EXIT-NORMAL: AX = NO_ERROR                                               */
/*                                                                           */
/* EXIT-ERROR: AX = Error code                                              */
/*                                                                           */
/* SIDE EFFECTS:  See GlobalInit and SGCBInit headers.                       */
/*                                                                           */
/*****************************************************************************/
/* BMSINIT()                                                                 */

USHORT APIENTRY _loadds _saveregs BMSINIT()
{
   USHORT RC = NO_ERROR;                /* Return code */

   /************************************************************/
   /* Establish an exit list procedure for the current process */
   /************************************************************/
   RC = DosExitList(0xC001, (PFNEXITLIST)((ULONG)BMSEXITLIST | 0x00030000));

   if (RC == NO_ERROR)
     {
      if ((InitFlag & INITDONE) == FALSE)                            /* MDLL */
        RC = GlobalInit();               /* Get Mouse version number */
/*    if (RC == NO_ERROR) @T52 */
      RC = SGCBInit();                /* Screen Group Control Block Init */
     }
   return(RC);

}  /* END BMSINIT Routine */

/*****************************************************************************/
/*                                                                           */
/* SUBROUTINE NAME:   Bms_Set_Pointer_Draw                                   */
/*                                                                           */
/* DESCRIPTIVE NAME:  Set pointer draw procedure and DS                      */
/*                                                                           */
/* FUNCTION:   Qualify pointer draw device name with \DEV\ and establish     */
/*             the pointer draw procedure entry and DS for the caller's      */
/*             current screen group.                                         */
/*                                                                           */
/* NOTES:                                                                    */
/*                                                                           */
/* ENTRY POINTS: Bms_Set_Pointer_Draw                                        */
/*   LINKAGE: CALL NEAR                                                      */
/*                                                                           */
/* INPUT:  PointerDrawName - Address of ASCIIZ pointer draw name             */
/*         WorkNameArea - Temporary work area to qualify pointer draw name   */
/*         ConfigPtr - Display configuration information                     */
/*         MouseHandle - Mouse$ handle                                       */
/*         Ioctl - Set real or protect mode pointer draw IOCtl               */
/*                                                                           */
/* OUTPUT:  Fully-qualified pointer draw device name stored in WorkNameArea  */
/*                                                                           */
/* EXIT-NORMAL:  AX = 0, Pointer draw procedure established successfully     */
/*                                                                           */
/* EXIT-ERROR:  AX = Error code from DosOpen                                 */
/*              AX = Error code from DosDevIOCtl                             */
/*              AX = Error code from DrawRoutine.Error                       */
/*                                                                           */
/* SIDE EFFECTS:  None                                                       */
/*                                                                           */
/*****************************************************************************/

USHORT pascal Bms_Set_Pointer_Draw(PointerDrawName,WorkNameArea,DrawRoutine)

CHAR  far *       PointerDrawName;     /* Address of Pointer Draw Name      */
CHAR  far *       WorkNameArea;        /* Work Area to fully qualify name   */
PDrawData         DrawRoutine;         /* Pointer Draw entry and DS struct  */
{
   USHORT             DrawHandle;      /* Draw routine handle               */
   USHORT             ActionTaken;     /* DosOpen action taken              */
   USHORT RC;                          /* Return Code                       */

   /**************************************************/
   /* Initialize the work area with "\DEV\        "  */
   /**************************************************/
   strncpy((char far *)WorkNameArea,(char far *)SkeletonPtrName,14);

   /***********************************************************************/
   /* If the user specified name doesn't have "\DEV\        " prepended   */
   /* already, copy just the user supplied PointerDD name to WorkNameArea.*/
   /***********************************************************************/
   if (strnicmp((char far *)WorkNameArea,(char far *)PointerDrawName,5))
     strncpy((char far *)(WorkNameArea+5),(char far *)PointerDrawName,8);

   /*********************************************************************/
   /* If the user specified name has "\DEV\        " prepended already, */
   /* copy just the user supplied PointerDD name to WorkNameArea + 5.   */
   /*********************************************************************/
   else
     strncpy((char far *)(WorkNameArea+5),(char far *)(PointerDrawName+5),8);

   /**************************************************************************/
   /* Attempt to open the specified pointer draw device driver               */
   /**************************************************************************/
   RC = DosOpen(WorkNameArea,&DrawHandle,&ActionTaken,0L,0,1,0xC2,0L);

   if (RC == NO_ERROR)
     {

       /*********************************************************************/
       /* Obtain the pointer draw ring 0 entry address and data segment     */
       /*********************************************************************/
       DrawRoutine->Error = NO_ERROR;
       RC = DosDevIOCtl(DrawRoutine,0L,GETDRAW,PTRCONTROL,DrawHandle);

       /*********************************************************************/
       /* Return any error codes returned by the pointer draw device driver */
       /*********************************************************************/
       if ((RC == NO_ERROR) && (DrawRoutine->Error != NO_ERROR))
         RC = DrawRoutine->Error;

       DosClose(DrawHandle);
     }

   return(RC);

}  /* END BMS_SET_POINTER_DRAW Routine */

