/*static char *SCCSID = "@(#)router.c   6.14 92/06/08";*/
/****************************************************************************/
/*                                                                          */
/*                       IBM/Microsoft Confidential                         */
/*                                                                          */
/*                 Copyright (c) IBM Corporation  1987, 1991                */
/*                 Copyright (c) Microsoft Corp.  1987, 1991                */
/*                           All Rights Reserved                            */
/*                                                                          */
/****************************************************************************/

/*********************** START OF SPECIFICATIONS *****************************/
/*                                                                           */
/* Source File Name: ROUTER.C                                                */
/*                                                                           */
/* Descriptive Name: Mouse/Keyboard API Router and Non-Routed API's.         */
/*                                                                           */
/* Status: OS/2 Release 2.00                                                 */
/*                                                                           */
/* Function: This module contains the internal routine that forwards         */
/*           control to the appropriate Base or Alternate Keyboard           */
/*           or Mouse Subsystem for processing.  It also contains            */
/*           API's that have dependencies requiring special processing       */
/*           before being routed to a subsystem or API's that are processed  */
/*           in this component and not routed to a subsystem.                */
/*                                                                           */
/* Internal Entry Points:                                                    */
/*           ROUTER()  from API.C which contains all routed API's            */
/*           ROUTSMINIT() called from API.C KBDSHELLINIT and MOUSHELLINIT    */
/*                                                                           */
/* External Entry Points:                                                    */
/*           KBDFREEFOCUS()                                                  */
/*           KBDGETFOCUS()                                                   */
/*           KBDSWITCHFGND()   unpublished routine                           */
/*           KBDSETFGND()      published, but only Session Manager can call  */
/*           KBDREGISTER()                                                   */
/*           KBDDEREGISTER()                                                 */
/*           KBDSYNCH()                                                      */
/*           MOUREGISTER()                                                   */
/*           MOUDEREGISTER()                                                 */
/*           MOUSYNCH()                                                      */
/*                                                                           */
/* Data: Refer to Global data declarations below prolog                      */
/*                                                                           */
/* Notes:                                                                    */
/*   Dependencies: 0 must be an invalid selector.                            */
/*                 0 must be an invalid current process PID (EXCEPT when     */
/*                 the caller is Session Manager)                            */
/*                                                                           */
/*   Restrictions: This source file must be compiled with the compiler flag  */
/*                 naming the global data segment as CDATA because that is   */
/*                 the naming convention used in OS2CHAR.DLL.  The instance  */
/*                 data segment is named in SUBSYS.ASM as _DATA for the      */
/*                 same reason.                                              */
/*                                                                           */
/*********************** END OF SPECIFICATIONS *******************************/

/*****************************************************************************/
/*******   C H A N G E       H I S T O R Y   *********************************/
/*****************************************************************************/
/* @GDW  - 08/29/91 - PTR B726157 - Combine KIO and MIO into MKIO router     */
/* @GDW  - 09/11/91 - PTR B726826 - MMIOPH Table for KBD in wrong order.     */
/* @GDW  - 10/19/91 - PTR B728410 - Registered Subsystem address needs to    */
/*                                  have DosLoadModule and DosGetProcAddr    */
/*                                  API's called for each process.           */
/* @GDW  - 11/21/91 - PTR B728981 - KbdRegister failing when process that    */
/*                                  called it dies.                          */
/* @GDW  - 01/21/92 - PTR B731619 - KbdSynch API reenabled. Was NO-OP.       */
/*                                  MouSynch API reenabled. Was NO-OP.       */
/* @GDW  - 02/28/92 - PTR B733895 - RoutExitList is TRAP D when a application*/
/*                                  exits due to AKS_Addr being invalid.     */
/* @GDW  - 02/28/92 - PTR B733730 - KbdDeRegister is not releasing memory    */
/*                                  attained from DOSSMGETMEM API.           */
/* @GDW  - 03/12/92 - PTR B734555 - KbdSynch and MouSynch are setting the    */
/*                                  wait state for the semaphore incorrectly.*/
/* @GDW  - 01/21/93 - DEF 059591  - <CONTL BREAK> causing deadlock.          */
/* @GDW  - 02/02/93 - DEF 061231  - KbdCharIn() MMIO wrong output.           */
/* @GDW  - 02-09-93 - DEF 061793  - <CTRL C> in OS/2 Window causes deadlock  */
/*                                  added wait parm to KbdGetSemaphore and   */
/*                                  moved check for <CTRL C> into function   */
/*                                  KbdGetSemaphore.                         */
/* @GDW  - 03/02/93 - DEF 063131  - An application using KbdRegister cannot  */
/*                                  use the registered API's from a different*/
/*                                  process.                                 */
/* @GDW  - 03/23/93 - DEF 063946  - "TYPE CONFIG.SYS | MORE" causes keyboard */
/*                                  focus to be lost.                        */
/* @GDW  - 08/30/93 - DEF 072823  - Cleanup routine ROUTEXITLIST called      */
/*                                  KbdDeRegister causing CUE.EXE to work    */
/*                                  incorrectly.                             */
/* @LLM  - 10/27/93 - DEF 073844  - Moved the check for an indefinite wait in*/
/*                                  kbdfreefocus and kbdgetfocus.            */

/*****************************************************************************/
/*******   Defines for inclusion of required typedefs, etc... ****************/
/*****************************************************************************/

#define INCL_ERRORS
#define INCL_DOSSEMAPHORES
#define INCL_DOSPROCESS
#define INCL_DOSINFOSEG
#define INCL_DOSMODULEMGR
#define INCL_KBD
#define INCL_MOU

#include <os2.h>
#include <dos.h>
#include <infoseg.h>
#include <string.h>
#include "smrsgcb.h"
#include "router.h"

/*****************************************************************************/
/* External procedures                                           Located in: */
/*****************************************************************************/

extern USHORT APIENTRY DOSSMGETMEM(PALTCB, USHORT);          /* OS2CHAR.DLL  */
extern USHORT APIENTRY DOSSMFREEMEM(PALTCB);                 /* OS2CHAR.DLL  */
extern USHORT APIENTRY DOSSMGETSGCB(PSGCB, USHORT, USHORT);  /* OS2CHAR.DLL  */
extern USHORT GETFOCUSALTSUBSYS(VOID);                       /* SUBSYS.ASM   */
extern USHORT GETFOCUSBASESUBSYS(VOID);                      /* SUBSYS.ASM   */
extern USHORT FREEFOCUSALTSUBSYS(VOID);                      /* SUBSYS.ASM   */
extern USHORT FREEFOCUSBASESUBSYS(VOID);                     /* SUBSYS.ASM   */
extern USHORT KBDALTSUBSYS(VOID);                            /* SUBSYS.ASM   */
extern USHORT KBDBASESUBSYS(VOID);                           /* SUBSYS.ASM   */
extern USHORT MOUALTSUBSYS(VOID);                            /* SUBSYS.ASM   */
extern USHORT MOUBASESUBSYS(VOID);                           /* SUBSYS.ASM   */
extern USHORT CHARINBASESUBSYS(VOID);                        /* SUBSYS.ASM   */
extern USHORT CHARINALTSUBSYS(VOID);                         /* SUBSYS.ASM   */
extern USHORT STRINGINBASESUBSYS(VOID);                      /* SUBSYS.ASM   */
extern USHORT STRINGINALTSUBSYS(VOID);                       /* SUBSYS.ASM   */
extern USHORT KbdCheckProcType(VOID);                        /* UTIL.C       */
extern USHORT KbdGetSemaphore(ULONG);                        /* UTIL.C       */
extern VOID   KbdClearSemaphore(VOID);                       /* UTIL.C       */
extern USHORT MouCheckProcType(VOID);                        /* UTIL.C       */
extern USHORT MouGetSemaphore(USHORT);                       /* UTIL.C       */
extern VOID   MouClearSemaphore(USHORT);                     /* UTIL.C       */
extern USHORT CheckRegisterParms(PSZ, PSZ, ULONG);           /* UTIL.C       */
extern USHORT KbdReloadAltSubSys(VOID);                      /* UTIL.C       */
extern USHORT MouReloadAltSubSys(VOID);                      /* UTIL.C       */
extern USHORT APIENTRY DosSetFgnd(USHORT, USHORT);

/*****************************************************************************/
/* Common data declarations - Global Variables (lower case vars with '_')    */
/*****************************************************************************/

USHORT (APIENTRY *BMS_Addr)(VOID) = 0L;  /* BMS entry address                */
USHORT (APIENTRY *BKS_Addr)(VOID) = 0L;  /* BKS entry address                */
CHAR    moudd_name[]  = "\\DEV\\MOUSE$";/* Mouse Device Driver name          */
CHAR    kbddd_name[]  = "\\DEV\\KBD$";  /* Keyboard Device Driver name       */
CHAR    bms_entrypoint[] = "BMSMAIN";   /* Base Mouse Subsystem entry name   */
CHAR    bms_modname[]    = "BMSCALLS";  /* Base Mouse Subsystem DLL name     */
CHAR    bks_entrypoint[] = "BKSMAIN";   /* Base Keyboard Subsystem entry name*/
CHAR    bks_modname[]    = "BKSCALLS";  /* Base Keyboard Subsystem DLL name  */
USHORT  moudd_exists     = 0;           /* Mouse Device Driver exists flag   */
USHORT  sesmgr_pid       = 0;           /* Session Manager process ID        */
USHORT  global_initflag  = 0;           /* Global Initialization Flag        */
PGDTINFOS global_info    = 0L;          /* Global information address        */
USHORT  mourout_ret      = 0;           /* save return address to router()   */
USHORT  kbdrout_ret      = 0;           /* save return address to router()   */

#ifdef MMIOPH                           /* MMIOPH Performance support        */

  extern VOID   MMIOKBDTrace(USHORT, USHORT);                /* UTIL.C       */
  extern VOID   MMIOMOUTrace(USHORT, USHORT);                /* UTIL.C       */

  SEL   mmio_sel         = 0;           /* Memory Mapped I/O selector        */
  USHORT FAR *mmio_buffer = 0L;         /* Addr. of memory mapped I/O buffer */
  USHORT mou_mmio_codes[MOU_HOOKS] = {  /* PRE MMIO trace hooks -            */
/* B726826 */                           /*     HI byte (6A) = major code     */
                                        /*     LO byte      = minor code     */
                           0x6A02,      /* PREgetnumbuttons                  */
                           0x6A03,      /* PREgetnummickeys                  */
                           0x6A04,      /* PREgetdevstatus                   */
                           0x6A06,      /* PREgetnumqueel                    */
                           0x6A05,      /* PREreadeventque                   */
                           0x6A08,      /* PREgetscalefact                   */
                           0x6A07,      /* PREgeteventmask                   */
                           0x6A09,      /* PREsetscalefact                   */
                           0x6A0A,      /* PREseteventmask                   */
                           0x6A19,      /* PREgetthreshold                   */
                           0x6A1A,      /* PREsetthreshold                   */
                           0x6A0B,      /* PREopen                           */
                           0x6A0C,      /* PREclose                          */
                           0x6A13,      /* PREgetptrshape                    */
                           0x6A0D,      /* PREsetptrshape                    */
                           0x6A0F,      /* PREdrawptr                        */
                           0x6A0E,      /* PREremoveptr                      */
                           0x6A14,      /* PREgetptrpos                      */
                           0x6A15,      /* PREsetptrpos                      */
                           0x6A16,      /* PREinitreal                       */
                           0x6A17,      /* PREflushque                       */
                           0x6A18,      /* PREsetdevstatus                   */
                           0x6A01,      /* PREregister                       */
                           0x6A11,      /* PREderegister                     */
                           0x6A1B,      /* PREshellinit                      */
                           0x6A1C,      /* PREsynch                          */

                           0x6A82,      /* POSTgetnumbuttons                 */
                           0x6A83,      /* POSTgetnummickeys                 */
                           0x6A84,      /* POSTgetdevstatus                  */
                           0x6A86,      /* POSTgetnumqueel                   */
                           0x6A85,      /* POSTreadeventque                  */
                           0x6A88,      /* POSTgetscalefact                  */
                           0x6A87,      /* POSTgeteventmask                  */
                           0x6A89,      /* POSTsetscalefact                  */
                           0x6A8A,      /* POSTseteventmask                  */
                           0x6A99,      /* POSTgetthreshold                  */
                           0x6A9A,      /* POSTsetthreshold                  */
                           0x6A8B,      /* POSTopen                          */
                           0x6A8C,      /* POSTclose                         */
                           0x6A93,      /* POSTgetptrshape                   */
                           0x6A8D,      /* POSTsetptrshape                   */
                           0x6A8F,      /* POSTdrawptr                       */
                           0x6A8E,      /* POSTremoveptr                     */
                           0x6A94,      /* POSTgetptrpos                     */
                           0x6A95,      /* POSTsetptrpos                     */
                           0x6A96,      /* POSTinitreal                      */
                           0x6A97,      /* POSTflushque                      */
                           0x6A98,      /* POSTsetdevstatus                  */
                           0x6A81,      /* POSTregister                      */
                           0x6A91,      /* POSTderegister                    */
                           0x6A9B,      /* POSTshellinit                     */
                           0x6A9C};     /* POSTsynch                         */

  USHORT kbd_mmio_codes[KBD_HOOKS] = {  /* PRE MMIO trace hooks -            */
                                        /*     HI byte (64) = major code     */
                                        /*     LO byte      = minor code     */
                           0x6403,      /* PREcharin                         */
                           0x6405,      /* PREpeek                           */
                           0x6404,      /* PREflushbuffer                    */
                           0x6407,      /* PREgetstatus                      */
                           0x6406,      /* PREsetstatus                      */
                           0x6408,      /* PREstringin                       */
                           0x640A,      /* PREopen                           */
                           0x640B,      /* PREclose                          */
                           0x640C,      /* PREgetfocus                       */
                           0x640D,      /* PREfreefocus                      */
                           0x640E,      /* PREgetcp                          */
                           0x640F,      /* PREsetcp                          */
                           0x6410,      /* PRExlate                          */
                           0x6411,      /* PREsetcustxt                      */
                           0x6402,      /* PREregister                       */
                           0x6409,      /* PREderegister                     */
                           0x6412,      /* PREgethwid                        */
                           0x6413,      /* PREsetfgnd                        */
                           0x6414,      /* PREshellinit                      */
                           0x6415,      /* PREsynch                          */

                           0x6483,      /* POSTcharin                        */
                           0x6485,      /* POSTpeek                          */
                           0x6484,      /* POSTflushbuffer                   */
                           0x6487,      /* POSTgetstatus                     */
                           0x6486,      /* POSTsetstatus                     */
                           0x6488,      /* POSTstringin                      */
                           0x648A,      /* POSTopen                          */
                           0x648B,      /* POSTclose                         */
                           0x648C,      /* POSTgetfocus                      */
                           0x648D,      /* POSTfreefocus                     */
                           0x648E,      /* POSTgetcp                         */
                           0x648F,      /* POSTsetcp                         */
                           0x6490,      /* POSTxlate                         */
                           0x6491,      /* POSTsetcustxt                     */
                           0x6482,      /* POSTregister                      */
                           0x6489,      /* POSTderegister                    */
                           0x6492,      /* POSTgethwid                       */
                           0x6493,      /* POSTsetfgnd                       */
                           0x6494,      /* POSTshellinit                     */
                           0x6495};     /* POSTsynch                         */
#endif

/*********************** START OF SPECIFICATIONS *****************************/
/*                                                                           */
/* SUBROUTINE NAME: Router                                                   */
/*                                                                           */
/* DESCRIPTIVE NAME: Mouse/Keyboard API router                               */
/*                                                                           */
/* FUNCTION: Route the mouse and keyboard APIs to the current screen groups  */
/*           base or alternate mouse/keyboard subsystem entry point.         */
/*                                                                           */
/* NOTES: The determination of whether to call the BMS/BKS or the AMS/AKS is */
/*        made based on the API being registered in the function mask. All   */
/*        API calls not replaced by the Alternate Subsystem are passed to    */
/*        the Base Subsystem.  Checking to see if the AMS/AKS has replaced   */
/*        only replaceable API's is done in MOUREGISTER and KBDREGISTER.     */
/*                                                                           */
/* ENTRY POINT: Router(RoutCode, APIOrdinal)                                 */
/*     LINKAGE: CALL NEAR                                                    */
/*                                                                           */
/* INPUT: RoutCode   - Flag indicating MOU or KBD API call and which API     */
/*                                                                           */
/* EXIT-NORMAL: RC = NO_ERROR                                                */
/*                                                                           */
/* EXIT-ERROR: RC = error codes from the AMS/BMS or AKS/BKS and error codes  */
/*                  returned from KbdCheckProcType and MouCheckProcType.     */
/*                                                                           */
/* EXTERNAL                                                                  */
/* REFERENCES:                                                               */
/*   ROUTINES: KBDALTSUBSYS() - fixes stack frame to published state and     */
/*                              calls the alternate subsystem for processing */
/*             KBDBASESUBSYS() - fixes stack frame to published state and    */
/*                               calls the base subsystem for processing     */
/*             MOUALTSUBSYS() - fixes stack frame to published state and     */
/*                              calls the alternate subsystem for processing */
/*             MOUBASESUBSYS() - fixes stack frame to published state and    */
/*                               calls the base subsystem for processing     */
/*                                                                           */
/*********************** END OF SPECIFICATIONS *******************************/

#pragma optimize("",off)
USHORT pascal _loadds _saveregs Router(USHORT RoutCode) {

  USHORT RC = NO_ERROR;

  if (RoutCode & KBDMASK) {
    RoutCode &= ROUTCODEMASK;

    #ifdef MMIOPH
      if (global_info->SIS_mec_table[SIS_KBDMEC] & KBD_TRACEMASK)
        MMIOKBDTrace(RoutCode,KBD_PREBASE);
    #endif

    RC = KbdCheckProcType();
    if (RC == NO_ERROR) {
      RC = KbdGetSemaphore(SEM_INDEFINITE_WAIT);           /* 063946  */
      if (RC == NO_ERROR) {
        RC = CALLBASESUB;
        if (SGData->KBD_Mask)
          if (SGData->KBD_Mask & (1 << RoutCode)) {
            RC = KbdReloadAltSubSys();                     /* B733895 */
            if (RC == NO_ERROR)
              RC = KBDALTSUBSYS();
          }

        if (RC == CALLBASESUB)
          RC = KBDBASESUBSYS();

        KbdClearSemaphore();
      }
    }

    #ifdef MMIOPH
      if (global_info->SIS_mec_table[SIS_KBDMEC] & KBD_TRACEMASK)
        MMIOKBDTrace(RoutCode, KBD_POSTBASE);
    #endif
  }
  else {

    #ifdef MMIOPH
      if (global_info->SIS_mec_table[SIS_MOUMEC] & MOU_TRACEMASK)
        MMIOMOUTrace(RoutCode,MOU_PREBASE);
    #endif

    RC = MouCheckProcType();
    if (RC == NO_ERROR) {
      RC = MouGetSemaphore(RoutCode);
      if (RC == NO_ERROR) {
        RC = CALLBASESUB;

        if (SGData->MOU_Mask) {
          if (SGData->MOU_Mask & (1 << RoutCode)) {
            RC = MouReloadAltSubSys();                     /* B733895 */
            if (RC == NO_ERROR)
              RC = MOUALTSUBSYS();
          }
        }

        if (RC == CALLBASESUB)
          RC = MOUBASESUBSYS();

        MouClearSemaphore(RoutCode);
      }
    }

    #ifdef MMIOPH
      if (global_info->SIS_mec_table[SIS_MOUMEC] & MOU_TRACEMASK)
        MMIOMOUTrace(RoutCode, MOU_POSTBASE);
    #endif
  }

  return(RC);
}
#pragma optimize("",on)

/*********************** START OF SPECIFICATIONS *****************************/
/*                                                                           */
/* SUBROUTINE NAME: KbdCharIn                                                */
/*                                                                           */
/* DESCRIPTIVE NAME: This call gets a character from the keyboard device     */
/*                   driver and passes it back to caller in CharData parm.   */
/*                                                                           */
/*  FUNCTION:  Main worker routine allowing all keystrokes to be passed      */
/*             to caller via call to BKSMAIN and eventually, to the          */
/*             keyboard IOCTL function 74h, get character.                   */
/*                                                                           */
/* NOTES: none                                                               */
/*                                                                           */
/* ENTRY POINT: KbdCharin                                                    */
/*     LINKAGE: CALL FAR from application                                    */
/*                                                                           */
/* INPUT: CharData = is the data record supplied to hold keystroke data.     */
/* INPUT: IOWait = is either NoWait (1) or Wait (0)                          */
/* INPUT: KbdHandle = is the handle that was retreived from the KbdOpen API  */
/*                   or the default handle 0.                                */
/*                                                                           */
/*  EXIT-NORMAL:  RC = NO_ERROR                                              */
/*                                                                           */
/*  EXIT-ERROR:  RC = (375) ERROR_KBD_INVALID_IOWAIT    MKIO                 */
/*               RC = (439) ERROR_KBD_INVALID_HANDLE    BKS                  */
/*               RC = (445) ERROR_KBD_FOCUS_REQUIRED    BKS                  */
/*               RC = (447) ERROR_KBD_KEYBOARD_BUSY     MKIO                 */
/*               RC = (464) ERROR_KBD_DETACHED          MKIO                 */
/*               RC = (504) ERROR_KBD_EXTENDED_SG       MKIO                 */
/*                                                                           */
/* INTERNAL REFERENCES:                                                      */
/*   INSTANCE data: none                                                     */
/*   COMMON data:   none                                                     */
/*                                                                           */
/* EXTERNAL REFERENCES:                                                      */
/*   LOCAL info: none                                                        */
/*  GLOBAL info: none                                                        */
/*                                                                           */
/*********************** END OF SPECIFICATIONS *******************************/

#pragma optimize("",off)
APIRET APIENTRY _loadds _saveregs KBDCHARIN(PKBDKEYINFO CharData,
                                            USHORT IOWait,
                                            HKBD Handle) {

  USHORT RC = NO_ERROR;
  ULONG  TEMP;

  #ifdef MMIOPH
    if (global_info->SIS_mec_table[SIS_KBDMEC] & KBD_TRACEMASK)
      MMIOKBDTrace(FC_KBDCHARIN,KBD_PREBASE);
  #endif

  if (IOWait == 1)               /* Do not wait for a keystroke          */
    TEMP = 0;                    /* NO Wait option                       */
  else if (IOWait == 0)          /* Wait until a keystroke is availible. */
    TEMP = -1L;                  /* Wait indefinite option               */
  else
    RC = ERROR_KBD_INVALID_IOWAIT;

  if (RC == NO_ERROR) {
    RC = KbdCheckProcType();
    if (RC == NO_ERROR) {
      RC = KbdGetSemaphore(TEMP);  /* 059591 */
      if (RC == NO_ERROR) {
        RC = CALLBASESUB;
        if (SGData->KBD_Mask) {
          if (SGData->KBD_Mask & (1L << FC_KBDCHARIN)) {
            RC = KbdReloadAltSubSys();
            if (RC == NO_ERROR)
              RC = CHARINALTSUBSYS();
          }
        }

        if (RC == CALLBASESUB)
          RC = CHARINBASESUBSYS();

        KbdClearSemaphore();
      }
      else
        RC = ERROR_KBD_KEYBOARD_BUSY;
    }

  } /* endif IOWAIT ERROR */

  #ifdef MMIOPH
    if (global_info->SIS_mec_table[SIS_KBDMEC] & KBD_TRACEMASK) {
      *mmio_buffer = kbd_mmio_codes[FC_KBDCHARIN+KBD_POSTBASE];
       mmio_buffer  = MAKEP(mmio_sel,12);       /* 061231 */
       *mmio_buffer = RC;
       *mmio_buffer = CharData->chChar;
       *mmio_buffer = CharData->chScan;
       *mmio_buffer = CharData->fbStatus;
       *mmio_buffer = CharData->bNlsShift;
       *mmio_buffer = CharData->fsState;
       mmio_buffer  = MAKEP(mmio_sel,4);
    }
  #endif

  return(RC);
}
#pragma optimize("",on)

/*********************** START OF SPECIFICATIONS *****************************/
/*                                                                           */
/* SUBROUTINE NAME: KbdStringIn                                              */
/*                                                                           */
/* DESCRIPTIVE NAME: This call gets a character from the keyboard device     */
/*                   driver and passes it back to caller in CharData parm.   */
/*                                                                           */
/*  FUNCTION:  Main worker routine allowing all keystrokes to be passed      */
/*             to caller via call to BKSMAIN and eventually, to the          */
/*             keyboard IOCTL function 74h, get character.                   */
/*                                                                           */
/* NOTES: none                                                               */
/*                                                                           */
/* ENTRY POINT: KbdCharin                                                    */
/*     LINKAGE: CALL FAR from application                                    */
/*                                                                           */
/* INPUT: CharData = is the data record supplied to hold keystroke data.     */
/* INPUT: IOWait = is either NoWait (1) or Wait (0)                          */
/* INPUT: KbdHandle = is the handle that was retreived from the KbdOpen API  */
/*                   or the default handle 0.                                */
/*                                                                           */
/*  EXIT-NORMAL:  RC = NO_ERROR                                              */
/*                                                                           */
/*  EXIT-ERROR:  RC = (375) ERROR_KBD_INVALID_IOWAIT                         */
/*               RC = (439) ERROR_KBD_INVALID_HANDLE                         */
/*               RC = (445) ERROR_KBD_FOCUS_REQUIRED                         */
/*               RC = (447) ERROR_KBD_KEYBOARD_BUSY                          */
/*               RC = (464) ERROR_KBD_DETACHED                               */
/*               RC = (504) ERROR_KBD_EXTENDED_SG                            */
/*                                                                           */
/* INTERNAL REFERENCES:                                                      */
/*   INSTANCE data: none                                                     */
/*   COMMON data:   none                                                     */
/*                                                                           */
/* EXTERNAL REFERENCES:                                                      */
/*   LOCAL info: none                                                        */
/*  GLOBAL info: none                                                        */
/*                                                                           */
/*********************** END OF SPECIFICATIONS *******************************/

#pragma optimize("",off)
USHORT APIENTRY _loadds _saveregs KBDSTRINGIN(PCH CharBuffer,
                                              PSTRINGINBUF StringLength,
                                              USHORT IOWait,
                                              HKBD Handle) {

  USHORT RC = NO_ERROR;
  ULONG  TEMP;

  #ifdef MMIOPH
    if (global_info->SIS_mec_table[SIS_KBDMEC] & KBD_TRACEMASK)
      MMIOKBDTrace(FC_KBDSTRINGIN,KBD_PREBASE);
  #endif

  if (IOWait == 1)               /* Do not wait for a keystroke          */
    TEMP = 0;                    /* NO Wait option                       */
  else if (IOWait == 0)          /* Wait until a keystroke is availible. */
    TEMP = -1L;                  /* Wait indefinite option               */
  else
    RC = ERROR_KBD_INVALID_IOWAIT;

  if (RC == NO_ERROR) {
    RC = KbdCheckProcType();
    if (RC == NO_ERROR) {
      RC = KbdGetSemaphore(TEMP);  /* 059591 */
      if (RC == NO_ERROR) {
        RC = CALLBASESUB;
        if (SGData->KBD_Mask) {
          TEMP = 1 << FC_KBDSTRINGIN;
          if (SGData->KBD_Mask & TEMP) {
            RC = KbdReloadAltSubSys();
            if (RC == NO_ERROR)
              RC = STRINGINALTSUBSYS();
          }
        }

        if (RC == CALLBASESUB)
          RC = STRINGINBASESUBSYS();

        KbdClearSemaphore();
      }
      else
        RC = ERROR_KBD_KEYBOARD_BUSY;
    }

  } /* endif IOWAIT ERROR  */

  #ifdef MMIOPH
    if (global_info->SIS_mec_table[SIS_KBDMEC] & KBD_TRACEMASK)
      MMIOKBDTrace(FC_KBDSTRINGIN, KBD_POSTBASE);
  #endif

  return(RC);
} /* END KbdStringIn */
#pragma optimize("",on)

/*********************** START OF SPECIFICATIONS ***************************/
/*                                                                         */
/* SUBROUTINE NAMES: KBDFREEFOCUS                                          */
/*                                                                         */
/* DESCRIPTIVE NAMES: Free keyboard focus                                  */
/*                                                                         */
/* FUNCTIONS: Release the bond on the specified logical keyboard           */
/*                                                                         */
/* NOTES: Must be issued by the last thread in a screen group that         */
/*        successfully issued KBDGETFOCUS.                                 */
/*                                                                         */
/* ENTRY POINTS: KBDFREEFOCUS                                              */
/*     LINKAGES: FAR CALL (external API)                                   */
/*                                                                         */
/* INPUT: KBDHANDLE - keyboard handle (WORD)                               */
/*                                                                         */
/* EXIT-NORMAL: RC = NO_ERROR                                              */
/*                                                                         */
/* EXIT-ERROR: RC = ERROR_KBD_FOCUS_ALREADY_ACTIVE                         */
/*                  ERROR_KBD_KEYBOARD_BUSY                                */
/*             RC = error code from subsystem                              */
/*                                                                         */
/* EFFECTS: None.                                                          */
/*                                                                         */
/* INTERNAL                                                                */
/* REFERENCES: None.                                                       */
/*   ROUTINES: FREEFOCUSALTSUBSYS() - fixes stack frame to published       */
/*                                    state and calls the Alternate        */
/*                                    Subsystem for processing             */
/*             FREEFOCUSBASESUBSYS() - fixes stack frame to published      */
/*                                     state and calls the Base            */
/*                                     Subsystem for processing            */
/*                                                                         */
/* EXTERNAL                                                                */
/* REFERENCES: None.                                                       */
/*   ROUTINES: AKS/BKS - Alternate/Base Keyboard Subsystem                 */
/*                                                                         */
/*********************** END OF SPECIFICATIONS *****************************/

#pragma optimize("",off)
USHORT APIENTRY _loadds _saveregs KBDFREEFOCUS(HKBD Handle) {
  USHORT RC;
  ULONG  TEMP;

  #ifdef MMIOPH
    if (global_info->SIS_mec_table[SIS_KBDMEC] & KBD_TRACEMASK)
      MMIOKBDTrace(FC_KBDFREEFOCUS, KBD_PREBASE);
  #endif

  if (SGData->KBD_FocusHandle != -1) {                      /* 73844 */
     RC = KbdCheckProcType();
     if (RC == NO_ERROR) {
       RC = KbdGetSemaphore(SEM_INDEFINITE_WAIT);           /* 063946  */
       if (RC == NO_ERROR) {
         RC = CALLBASESUB;
         if (SGData->KBD_Mask) {
           TEMP = 1 << FC_KBDFREEFOCUS;
           if (SGData->KBD_Mask & TEMP) {
             RC = KbdReloadAltSubSys();                     /* B733895 */
             if (RC == NO_ERROR)
               RC = FREEFOCUSALTSUBSYS();
           }
         }
         if (RC == CALLBASESUB) {
             RC = FREEFOCUSBASESUBSYS();
             if (RC == NO_ERROR) {
               SGData->KBD_FocusHandle = -1;
               SGData->KBD_FocusPID = 0;
             }
         }
         KbdClearSemaphore();           /* Clear this thread sem ownership */
       }
     }
  }
  else
    RC = ERROR_KBD_FOCUS_REQUIRED;

/******************************* 73844 *************************************/
/*  RC = KbdCheckProcType();                                               */
/*  if (RC == NO_ERROR) {                                                  */
/*    RC = KbdGetSemaphore(SEM_INDEFINITE_WAIT);             063946        */
/*    if (RC == NO_ERROR) {                                                */
/*      RC = CALLBASESUB;                                                  */
/*      if (SGData->KBD_Mask) {                                            */
/*        TEMP = 1 << FC_KBDFREEFOCUS;                                     */
/*        if (SGData->KBD_Mask & TEMP) {                                   */
/*          RC = KbdReloadAltSubSys();                        B733895      */
/*          if (RC == NO_ERROR)                                            */
/*            RC = FREEFOCUSALTSUBSYS();                                   */
/*        }                                                                */
/*      }                                                                  */
/*                                                                         */
/*      if (RC == CALLBASESUB) {                                           */
/*        if (SGData->KBD_FocusHandle != -1) {                             */
/*          RC = FREEFOCUSBASESUBSYS();                                    */
/*          if (RC == NO_ERROR) {                                          */
/*            SGData->KBD_FocusHandle = -1;                                */
/*            SGData->KBD_FocusPID = 0;                                    */
/*          }                                                              */
/*        }                                                                */
/*        else                                                             */
/*          RC = ERROR_KBD_FOCUS_REQUIRED;                                 */
/*      }                                                                  */
/*                                                                         */
/*  KbdClearSemaphore();                Clear this thread sem ownership    */
/*  }                                                                      */
/*}                                                                        */
/*                                                                         */
/******************************* 73844 *************************************/

  #ifdef MMIOPH
    if (global_info->SIS_mec_table[SIS_KBDMEC] & KBD_TRACEMASK)
      MMIOKBDTrace(FC_KBDFREEFOCUS,KBD_POSTBASE);
  #endif

  return(RC);
}
#pragma optimize("",on)

/*********************** START OF SPECIFICATIONS ***************************/
/*                                                                         */
/* SUBROUTINE NAMES: KBDGETFOCUS                                           */
/*                                                                         */
/* DESCRIPTIVE NAMES: Get keyboard focus                                   */
/*                                                                         */
/* FUNCTIONS: Bind the logical keyboard specified to the physical          */
/*            device.                                                      */
/*                                                                         */
/* NOTES: There can be at most 1 outstanding KbdGetFocus per screen        */
/*        group.  After a successful KbdGetFocus call, all keystrokes      */
/*        for that screen group will go to the thread that owns the        */
/*        semaphore.                                                       */
/*                                                                         */
/* ENTRY POINTS: KbdGetFocus                                               */
/*     LINKAGES: FAR CALL (external API)                                   */
/*                                                                         */
/* INPUT: IOWAIT - wait/nowait flag (WORD)                                 */
/*                 0 = caller wants to wait for bond                       */
/*                 1 = caller does not want to wait for bond               */
/*        KBDHANDLE - keyboard handle (WORD)                               */
/*                                                                         */
/* EXIT-NORMAL: RC = NO_ERROR                                              */
/*                                                                         */
/* EXIT-ERROR: RC = ERROR_KBD_KEYBOARD_BUSY                                */
/*             RC = ERROR_KBD_FOCUS_ALREADY_ACTIVE                         */
/*             RC = error code from subsystem                              */
/*                                                                         */
/* EFFECTS: None.                                                          */
/*                                                                         */
/* INTERNAL                                                                */
/* REFERENCES: focus - 1=focus for current PID  0=no focus for current PID */
/*   ROUTINES: GETFOCUSALTSUBSYS() - fixes stack frame to published        */
/*                                   state and calls the Alternate         */
/*                                   Subsystem for processing              */
/*             GETFOCUSBASESUBSYS() - fixes stack frame to published       */
/*                                    state and calls the Base             */
/*                                    Subsystem for processing             */
/*                                                                         */
/*                                                                         */
/*   ROUTINES: None.                                                       */
/*                                                                         */
/* EXTERNAL                                                                */
/* REFERENCES: None.                                                       */
/*   ROUTINES: AKS/BKS - Alternate/Base Keyboard Subsystem                 */
/*                                                                         */
/*********************** END OF SPECIFICATIONS *****************************/

#pragma optimize("",off)
USHORT APIENTRY _loadds _saveregs KBDGETFOCUS(USHORT IOWait, HKBD Handle) {
  USHORT RC = NO_ERROR;
  ULONG  WaitFlag;

  #ifdef MMIOPH
    if (global_info->SIS_mec_table[SIS_KBDMEC] & KBD_TRACEMASK)
      MMIOKBDTrace(FC_KBDGETFOCUS, KBD_PREBASE);
  #endif

  if (IOWait == SEM_RETURN)
    WaitFlag = SEM_IMMEDIATE_RETURN;
  else if (IOWait == SEM_WAIT)
    WaitFlag = SEM_INDEFINITE_WAIT;
  else
    RC = ERROR_KBD_INVALID_IOWAIT;

  if (SGData->KBD_FocusHandle == -1) {                         /* 73844 */
     if (RC == NO_ERROR) {
        RC = KbdCheckProcType();
        if (RC == NO_ERROR) {
           RC = KbdGetSemaphore(WaitFlag);                     /* 059591 */
           if (RC == NO_ERROR) {
              RC = CALLBASESUB;
              if (SGData->KBD_Mask) {
                 WaitFlag = 1 << FC_KBDGETFOCUS;
                 if (SGData->KBD_Mask & WaitFlag) {
                    RC = KbdReloadAltSubSys();                  /* B733895 */
                    if (RC == NO_ERROR)
                       RC = GETFOCUSALTSUBSYS();
                 }
              }
              if (RC == CALLBASESUB) {
                 RC = GETFOCUSBASESUBSYS();
                 if (RC == NO_ERROR) {
                    SGData->KBD_FocusHandle = Handle;
                    SGData->KBD_FocusPID = CurrentPID;
                 }
              }
              KbdClearSemaphore();    /* Clear KbdGetFocus sem ownership   */
           }
         }
         else
              RC = ERROR_KBD_KEYBOARD_BUSY;
     }
  }
  else
     RC = ERROR_KBD_FOCUS_ALREADY_ACTIVE;

/******************************* 73844 *************************************/
/*                                                                         */
/*  if (RC == NO_ERROR) {                                                  */
/*    RC = KbdCheckProcType();                                             */
/*    if (RC == NO_ERROR) {                                                */
/*      RC = KbdGetSemaphore(WaitFlag);                        059591      */
/*      if (RC == NO_ERROR) {                                              */
/*        RC = CALLBASESUB;                                                */
/*        if (SGData->KBD_Mask) {                                          */
/*          WaitFlag = 1 << FC_KBDGETFOCUS;                                */
/*          if (SGData->KBD_Mask & WaitFlag) {                             */
/*            RC = KbdReloadAltSubSys();                     B733895       */
/*            if (RC == NO_ERROR)                                          */
/*              RC = GETFOCUSALTSUBSYS();                                  */
/*          }                                                              */
/*        }                                                                */
/*                                                                         */
/*        if (RC == CALLBASESUB) {                                         */
/*          if (SGData->KBD_FocusHandle == -1) {                           */
/*            RC = GETFOCUSBASESUBSYS();                                   */
/*            if (RC == NO_ERROR) {                                        */
/*              SGData->KBD_FocusHandle = Handle;                          */
/*              SGData->KBD_FocusPID = CurrentPID;                         */
/*            }                                                            */
/*          }                                                              */
/*          else                                                           */
/*            RC = ERROR_KBD_FOCUS_ALREADY_ACTIVE;                         */
/*        }                                                                */
/*                                                                         */
/*        KbdClearSemaphore();         Clear KbdGetFocus sem ownership     */
/*      }                                                                  */
/*      else                                                               */
/*        RC = ERROR_KBD_KEYBOARD_BUSY;                                    */
/*    }                                                                    */
/*}                                                                        */
/******************************* 73844 *************************************/

  #ifdef MMIOPH
    if (global_info->SIS_mec_table[SIS_KBDMEC] & KBD_TRACEMASK)
      MMIOKBDTrace(FC_KBDGETFOCUS,KBD_POSTBASE);
  #endif

  return(RC);
}
#pragma optimize("",on)

/******************* START OF SPECIFICATIONS ********************************/
/*                                                                          */
/*  SUBROUTINE NAME:  KbdRegister  (not replaceable by KbdRegister)         */
/*                                                                          */
/*  DESCRIPTIVE NAME:  Process KbdRegister API.                             */
/*                                                                          */
/*  FUNCTION:  Get address of Registered subsystem.                         */
/*                                                                          */
/*  ENTRY POINT:  KbdRegister                                               */
/*      LINKAGE:  CALL FAR                                                  */
/*                                                                          */
/*  INPUT:  ModuleName - Name of the DLL being processed                    */
/*          EntryPoint - Procedure name of DLL entry point.                 */
/*          Mask       - Mask indicating Keyboard API's being registered.   */
/*                                                                          */
/*  EXIT-NORMAL:  RC = NO_ERROR                                             */
/*                                                                          */
/*  EXIT-ERROR: error code from SetSemaphore()                              */
/*              ERROR_KBD_INVALID_MASK - Mask invalid                       */
/*              ERROR_KBD_INVALID_ASCIIZ - Modulename/EntryPoint Invalid    */
/*              ERROR_KBD_REGISTER - Previous KbdRegister outstanding in    */
/*                                   current Screen Group.                  */
/*                                                                          */
/*  EFFECTS:  The API KbdRegister is processed by getting addressibility    */
/*            to the subsystem being processed.                             */
/*                                                                          */
/* INTERNAL REFERENCES:                                                     */
/*   INSTANCE data: none                                                    */
/*                                                                          */
/*     COMMON data: none                                                    */
/*                                                                          */
/*        ROUTINES: SetSemaphore() - Called to synchronize calls through    */
/*                               the Router and check for Full Screen,      */
/*                               screen group which is the only valid screen*/
/*                               group allowed to make this API call.       */
/*                                                                          */
/*               DOSSMGETMEM() - Call to Session Manager to allocate        */
/*                               memory in the Screen Group Control Block.  */
/*                                                                          */
/*        CheckRegisterParms() - Validates the input parameters.            */
/*                                                                          */
/* EXTERNAL REFERENCES:                                                     */
/*      ROUTINES: DosLoadModule() - Get Entry Point to the subsystem.       */
/*                DosGetProcAddr() - Load address of subsystem .            */
/*                DosFreeModule() - Free the entry point to subsystem.      */
/*                                                                          */
/******************* END  OF  SPECIFICATIONS ********************************/

USHORT APIENTRY _loadds _saveregs KBDREGISTER(PSZ ModuleName,
                                              PSZ EntryPoint, ULONG Mask) {

  USHORT RC = NO_ERROR;

  #ifdef MMIOPH
    if (global_info->SIS_mec_table[SIS_KBDMEC] & KBD_TRACEMASK)
      MMIOKBDTrace(FC_KBDREGISTER,KBD_PREBASE);
  #endif

  if (CurrentSGID == PT_VIOPOPUP)
    RC = ERROR_KBD_REGISTER;
  else
    if (CurrentTYPE == LIS_PT_VIOWIN)
      RC = ERROR_KBD_REGISTER;
    else
      if (SGData->KBD_Mask)
        RC = ERROR_KBD_REGISTER;

  if (RC == NO_ERROR) {
    RC = KbdCheckProcType();
    if (RC == NO_ERROR) {
      RC = KbdGetSemaphore(SEM_INDEFINITE_WAIT);         /* 063946  */
      if (RC == NO_ERROR) {
        RC = CheckRegisterParms(ModuleName, EntryPoint, Mask);
        if (RC == NO_ERROR) {
          RC = DOSSMGETMEM((PALTCB)&SGData->KBD_AKSCB, CBSIZE);
          if (RC == NO_ERROR) {
            RC = DosLoadModule(NAMEBUFFER,
                               BUFFERLENGTH,
                               (PSZ)ModuleName,
                               &SGData->KBD_AKSCB->Handle);
            if (RC == NO_ERROR) {
              RC = DosGetProcAddr(SGData->KBD_AKSCB->Handle,
                                 (PSZ)EntryPoint,
                                 &AKS_Addr);              /* 063131 */
              if (RC == NO_ERROR) {
                /***********************************************************/
                /* SGData->KBD_Mask is also a flag used to indicate when a */
                /* KbdRegister() is in effect for this Screen Group.       */
                /***********************************************************/
                SGData->KBD_Mask = Mask;
                SGData->KBD_AKSCB->PID = CurrentPID;
                strcpy(SGData->KBD_AKSCB->EntryPoint, EntryPoint); /* B728410 */
                strcpy(SGData->KBD_AKSCB->ModuleName, ModuleName); /* B728410 */
              }
            }
          }
        }
        else {
          if (RC == REG_STRING_ERROR)
            RC = ERROR_KBD_INVALID_ASCIIZ;
          else
            RC = ERROR_KBD_INVALID_MASK;
        }

        KbdClearSemaphore();
      }
      else
        RC = ERROR_KBD_KEYBOARD_BUSY;
    }
  }

  #ifdef MMIOPH
    if (global_info->SIS_mec_table[SIS_KBDMEC] & KBD_TRACEMASK)
      MMIOKBDTrace(FC_KBDREGISTER,KBD_POSTBASE);
  #endif

  return(RC);
}

/******************* START OF SPECIFICATIONS ********************************/
/*                                                                          */
/*  SUBROUTINE NAME:  KbdDeRegister  (not replaceable by KbdRegister)       */
/*                                                                          */
/*  DESCRIPTIVE NAME:  Process KbdDeRegister API.                           */
/*                                                                          */
/*  FUNCTION: Reset the ASCIIZ module name, procedure name, and the         */
/*            function mask for the current screen group.                   */
/*                                                                          */
/*  NOTES: If the process issuing a KBDDEREGISTER call is not the same      */
/*         process that successfully issued a KBDREGISTER call, it will     */
/*         receive an error return code.                                    */
/*                                                                          */
/*  ENTRY POINT:  KbdDeRegister                                             */
/*      LINKAGE:  CALL FAR                                                  */
/*                                                                          */
/*  INPUT:  None                                                            */
/*                                                                          */
/*  EXIT-NORMAL:  RC = NO_ERROR                                             */
/*                                                                          */
/*  EXIT-ERROR: error code from SetSemaphore()                              */
/*           ERROR_KBD_DEREGISTER - Must be PID that called KbdRegister     */
/*                                  and KbdRegister must be have been       */
/*                                  successful for this Screen Group.       */
/*                                                                          */
/* INTERNAL REFERENCES:                                                     */
/*   INSTANCE data: none                                                    */
/*                                                                          */
/*     COMMON data: none                                                    */
/*                                                                          */
/*        ROUTINES: SetSemaphore() - Called to synchronize calls through    */
/*                               the Router and check for Full Screen,      */
/*                               screen group which is the only valid screen*/
/*                               group allowed to make these API calls.     */
/*                                                                          */
/* EXTERNAL REFERENCES:                                                     */
/*      ROUTINES: None                                                      */
/*                                                                          */
/******************* END  OF  SPECIFICATIONS ********************************/

USHORT APIENTRY _loadds _saveregs KBDDEREGISTER(VOID) {
  USHORT RC = NO_ERROR;

  #ifdef MMIOPH
    if (global_info->SIS_mec_table[SIS_KBDMEC] & KBD_TRACEMASK)
      MMIOKBDTrace(FC_KBDDEREGISTER, KBD_PREBASE);
  #endif

  if (CurrentSGID == PT_VIOPOPUP)
    RC = ERROR_KBD_DEREGISTER;
  else
    if (CurrentTYPE == LIS_PT_VIOWIN)
      RC = ERROR_KBD_DEREGISTER;

  if (RC == NO_ERROR) {
    RC = KbdCheckProcType();
    if (RC == NO_ERROR) {
      RC = KbdGetSemaphore(SEM_INDEFINITE_WAIT);          /* 063946  */
      if (RC == NO_ERROR) {
        if (SGData->KBD_AKSCB != 0L) {
          /***********************************************************/
          /* Allow only owners PID or PID that started screen group. */
          /***********************************************************/
          if (SGData->KBD_AKSCB->PID == CurrentPID ||
              SGData->SGCB_PID == CurrentPID) {           /* 072823 */
            DosFreeModule(SGData->KBD_AKSCB->Handle);
            DOSSMFREEMEM((PALTCB)SGData->KBD_AKSCB);      /* B733730 */
            SGData->KBD_Mask = 0L;
            SGData->KBD_AKSCB = 0L;
            AKS_Addr = 0L;
          }
          else
            RC = ERROR_KBD_DEREGISTER;
        }
        else
          RC = ERROR_KBD_DEREGISTER;

        KbdClearSemaphore();
      }
      else
        RC = ERROR_KBD_KEYBOARD_BUSY;
    }
  }

  #ifdef MMIOPH
    if (global_info->SIS_mec_table[SIS_KBDMEC] & KBD_TRACEMASK)
      MMIOKBDTrace(FC_KBDDEREGISTER, KBD_POSTBASE);
  #endif

  return(RC);
}

/*********************** START OF SPECIFICATIONS ***************************/
/*                                                                         */
/* SUBROUTINE NAME: KbdSetFGND                                             */
/*                                                                         */
/* DESCRIPTIVE NAME: Set current PID as current foreground PID.            */
/*                                                                         */
/* FUNCTION: Specifies which process should get the next keystroke.        */
/*                                                                         */
/* NOTES: None.                                                            */
/*                                                                         */
/* ENTRY POINT: KbdSetFGND                                                 */
/*     LINKAGE: FAR CALL  (external from Subsystem)                        */
/*                                                                         */
/* INPUT: none.                                                            */
/*                                                                         */
/* EXIT-NORMAL: AX = NO_ERROR                                              */
/*                                                                         */
/* EXIT-ERROR: AX = error code from DOSSETFGND                             */
/*                                                                         */
/* INTERNAL                                                                */
/* REFERENCES: none                                                        */
/*                                                                         */
/*   ROUTINES: none.                                                       */
/*                                                                         */
/* EXTERNAL                                                                */
/* REFERENCES: none.                                                       */
/*   ROUTINES: DOSSETFGND - set keyboard focus                             */
/*                                                                         */
/*********************** END OF SPECIFICATIONS *****************************/

USHORT APIENTRY _loadds _saveregs KBDSETFGND(VOID) {
  USHORT    RC = NO_ERROR;

  #ifdef MMIOPH
    if (global_info->SIS_mec_table[SIS_KBDMEC] & KBD_TRACEMASK)
      MMIOKBDTrace(FC_KBDSETFGND,KBD_PREBASE);
  #endif

  if (LocalInfo->LIS_CurScrnGrp == global_info->SIS_CurScrnGrp) {
    if (LocalInfo->LIS_CurProcID != global_info->SIS_FgndPID) {
      RC = DosSetFgnd(0,LocalInfo->LIS_CurProcID);
      if (RC == NO_ERROR)
        SGData->KBD_FGND_PID = LocalInfo->LIS_CurProcID;
    }
  }
  else
    RC = ERROR_KBD_KEYBOARD_BUSY;

  #ifdef MMIOPH
    if (global_info->SIS_mec_table[SIS_KBDMEC] & KBD_TRACEMASK)
      MMIOKBDTrace(FC_KBDSETFGND,KBD_POSTBASE);
  #endif

  return(RC);
}

/*********************** START OF SPECIFICATIONS ***************************/
/*                                                                         */
/* SUBROUTINE NAME: KBDSWITCHFGND                                          */
/*                                                                         */
/* DESCRIPTIVE NAME: Set keyboard focus on a screen switch                 */
/*                                                                         */
/* FUNCTION: Specifies which process should get the next keystroke.        */
/*                                                                         */
/* NOTES: None.                                                            */
/*                                                                         */
/* ENTRY POINT: KBDSWITCHFGND                                              */
/*     LINKAGE: FAR CALL  (external from Screen Switcher)                  */
/*                                                                         */
/* INPUT: SessionID - session ID being switched to.                        */
/*                                                                         */
/* EXIT-NORMAL: AX = NO_ERROR                                              */
/*                                                                         */
/* EXIT-ERROR: AX = error code from DOSSETFGND                             */
/*             AX = error code from DOSSMGETSGCB                           */
/*                                                                         */
/* INTERNAL                                                                */
/* REFERENCES: SGData->KBD_FGND_PID - current keyboard focus PID           */
/*             sesmgr_pid - Session Managers PID                           */
/*             CurrentPID - current process ID                             */
/*                                                                         */
/*   ROUTINES: None.                                                       */
/*                                                                         */
/* EXTERNAL                                                                */
/* REFERENCES: None.                                                       */
/*   ROUTINES: DOSSETFGND - set keyboard focus                             */
/*             DOSSMGETSGCB - get requested Screen Group Control Block     */
/*                                                                         */
/*********************** END OF SPECIFICATIONS *****************************/

USHORT APIENTRY _loadds _saveregs KBDSWITCHFGND(USHORT SessionID) {
  USHORT RC;

  if (CurrentPID == sesmgr_pid) {
    if (SGData->KBD_FGND_PID != 0)
      RC = DosSetFgnd(0,SGData->KBD_FGND_PID);
  }
  else
    RC = ERROR_KBD_SMG_ONLY;

  return(RC);
}

/*********************** START OF SPECIFICATIONS *****************************/
/*                                                                           */
/*                                     ******************************        */
/* SUBROUTINE NAME: RoutSMInit         ***  UNPUBLISHED  ROUTINE  ***        */
/*                                     ******************************        */
/*                                                                           */
/* DESCRIPTIVE NAME: Identify caller as the Session Manager process.         */
/*                                                                           */
/*  FUNCTION:  The first caller of RoutSMInit is the Session Manager.        */
/*                                                                           */
/* NOTES: This call is the first call to the ROUTER from the Session Manager */
/*        process. Called by Session Manager during system initialization.   */
/*                                                                           */
/* ENTRY POINT: RoutSMInit                                                   */
/*     LINKAGE: CALL NEAR (from API MouShellInit() and KbdShellInit().       */
/*                        The ShellInit calls are CALL FAR from Sesion Mgr.) */
/*                                                                           */
/* INPUT: ApiType = is either MOU or KBD                                     */
/*                                                                           */
/*  EXIT-NORMAL:  RC = MO_ERROR                                              */
/*                                                                           */
/*  EXIT-ERROR:  ERROR_MOUSE_SMG_ONLY -                                      */
/*               caller is NOT the Session Manager's process                 */
/*                                                                           */
/* INTERNAL REFERENCES:                                                      */
/*   INSTANCE data: CurrentProcID   - caller's process ID                    */
/*   COMMON data:   sesmgr_pid - first caller's PID                          */
/*                  moudd_exists - set to 1 iff DOSOPEN(MOUSE$) succeeds     */
/*                                                                           */
/* EXTERNAL REFERENCES:                                                      */
/*   LOCAL info: none                                                        */
/*  GLOBAL info: none                                                        */
/*                                                                           */
/*********************** END OF SPECIFICATIONS *******************************/

USHORT pascal _saveregs RoutSMInit(USHORT APIType) {
  USHORT  RC = NO_ERROR;
  USHORT  handle;                       /* Temporary device handle          */
  USHORT  action;                       /* Temporary device open action     */

  if (APIType == MOU) {
    #ifdef MMIOPH                                              /* B726826 */
      if (global_info->SIS_mec_table[SIS_MOUMEC] & MOU_TRACEMASK)
        MMIOMOUTrace(FC_MOUSHELLINIT,MOU_PREBASE);
    #endif

    /***********************************************************************/
    /* If sesmgr_pid non-zero, then Session Manager was previously called  */
    /***********************************************************************/
    if (!sesmgr_pid)
      sesmgr_pid = CurrentPID;            /* record the Session Manager's PID */

    /*********************************************************************/
    /* Check for mouse DD existence with DOSOPEN.                        */
    /*     This test is not in GlobalInit() because the Mouse Device     */
    /*     Driver has not been loaded at the time GlobalInit() is called.*/
    /*********************************************************************/
    RC = DosOpen(moudd_name, &handle, &action,
                 FILESIZE, FILEATTRIBUTE, OPENFLAG, OPENMODE, RESERVED);

    if (RC == NO_ERROR) {
      moudd_exists = TRUE;
      DosClose(handle);
    }
    else
      RC = ERROR_MOUSE_NO_DEVICE;

    #ifdef MMIOPH                                              /* B726826 */
      if (global_info->SIS_mec_table[SIS_MOUMEC] & MOU_TRACEMASK)
        MMIOMOUTrace(FC_MOUSHELLINIT,MOU_POSTBASE);
    #endif
  }
  else {
    #ifdef MMIOPH                                              /* B726826 */
      if (global_info->SIS_mec_table[SIS_KBDMEC] & KBD_TRACEMASK)
        MMIOKBDTrace(FC_KBDSHELLINIT,KBD_PREBASE);
    #endif

    /***********************************************************************/
    /* If sesmgr_pid non-zero, then Session Manager was previously called  */
    /***********************************************************************/
    if (!sesmgr_pid)
      sesmgr_pid = CurrentPID;            /* record the Session Manager's PID */
    else
      RC = ERROR_KBD_SMG_ONLY;

    #ifdef MMIOPH                                              /* B726826 */
      if (global_info->SIS_mec_table[SIS_KBDMEC] & KBD_TRACEMASK)
        MMIOKBDTrace(FC_KBDSHELLINIT,KBD_POSTBASE);
    #endif

  }

  return(RC);
}

/******************* START OF SPECIFICATIONS ********************************/
/*                                                                          */
/*  SUBROUTINE NAME:  MouRegister  (not replaceable by MouRegister)         */
/*                                                                          */
/*  DESCRIPTIVE NAME:  Process MouRegister API.                             */
/*                                                                          */
/*  FUNCTION:  Get address of Registered subsystem.                         */
/*                                                                          */
/*  ENTRY POINT:  MouRegister                                               */
/*      LINKAGE:  CALL FAR                                                  */
/*                                                                          */
/*  INPUT:  ModuleName - Name of the DLL being processed                    */
/*          EntryPoint - Procedure name of DLL entry point.                 */
/*          Mask       - Mask indicating Keyboard API's being registered.   */
/*                                                                          */
/*  EXIT-NORMAL:  RC = NO_ERROR                                             */
/*                                                                          */
/*  EXIT-ERROR: error code from SetSemaphore()                              */
/*              ERROR_MOUSE_INVALID_MASK - Mask invalid                     */
/*              ERROR_MOUSE_INVALID_ASCIIZ - Modulename/EntryPoint Invalid  */
/*              ERROR_MOUSE_REGISTER - Previous MouRegister outstanding in  */
/*                                     current Screen Group.                */
/*                                                                          */
/*  EFFECTS:  The API MouRegister is processed by getting addressibility    */
/*            to the subsystem being processed.                             */
/*                                                                          */
/* INTERNAL REFERENCES:                                                     */
/*   INSTANCE data: none                                                    */
/*                                                                          */
/*     COMMON data: none                                                    */
/*                                                                          */
/*        ROUTINES: SetSemaphore() - Called to synchronize calls through    */
/*                               the Router and check for Full Screen,      */
/*                               screen group which is the only valid screen*/
/*                               group allowed to make these API calls.     */
/*                                                                          */
/*               DOSSMGETMEM() - Call to Session Manager to allocate        */
/*                               memory in the Screen Group Control Block.  */
/*                                                                          */
/*        CheckRegisterParms() - Validates the input parameters.            */
/*                                                                          */
/* EXTERNAL REFERENCES:                                                     */
/*      ROUTINES: DosLoadModule() - Get Entry Point to the subsystem.       */
/*                DosGetProcAddr() - Load address of subsystem .            */
/*                DosFreeModule() - Free the entry point to subsystem.      */
/*                                                                          */
/******************* END  OF  SPECIFICATIONS ********************************/

USHORT APIENTRY _loadds _saveregs MOUREGISTER(PSZ ModuleName,
                                              PSZ EntryPoint, ULONG Mask) {
  USHORT RC = NO_ERROR;

  #ifdef MMIOPH
    if (global_info->SIS_mec_table[SIS_MOUMEC] & MOU_TRACEMASK)
      MMIOMOUTrace(FC_MOUREGISTER, MOU_PREBASE);
  #endif

  if (CurrentSGID == PT_VIOPOPUP)
    RC = ERROR_MOUSE_REGISTER;
  else
    if (CurrentTYPE == LIS_PT_VIOWIN)
      RC = ERROR_MOUSE_REGISTER;
    else
      if (SGData->MOU_Mask)
        RC = ERROR_MOUSE_REGISTER;

  if (RC == NO_ERROR) {
    RC = MouCheckProcType();
    if (RC == NO_ERROR) {
      RC = MouGetSemaphore(FC_MOUREGISTER);
      if (RC == NO_ERROR) {
        RC = CheckRegisterParms(ModuleName, EntryPoint, Mask);
        if (RC == NO_ERROR) {
          RC = DOSSMGETMEM((PALTCB)&SGData->MOU_AMSCB, CBSIZE);
          if (RC == NO_ERROR) {
            RC = DosLoadModule(NAMEBUFFER,
                               BUFFERLENGTH,
                               (PSZ)ModuleName,
                               &SGData->MOU_AMSCB->Handle);
            if (RC == NO_ERROR) {
              RC = DosGetProcAddr(SGData->MOU_AMSCB->Handle,
                                 (PSZ)EntryPoint,
                                 &AMS_Addr);              /* 063131 */

              /***********************************************************/
              /* SGData->MOU_Mask is also a flag used to indicate when a */
              /* MouRegister() is in effect for this Screen Group.       */
              /***********************************************************/
              if (RC == NO_ERROR) {
                SGData->MOU_Mask = Mask;
                SGData->MOU_AMSCB->PID = CurrentPID;
                strcpy(SGData->MOU_AMSCB->EntryPoint, EntryPoint); /* B728410 */
                strcpy(SGData->MOU_AMSCB->ModuleName, ModuleName); /* B728410 */
              }
            }
          }
        }
        else {
          if (RC == REG_STRING_ERROR)
            RC = ERROR_MOUSE_INVALID_ASCIIZ;
          else
            RC = ERROR_MOUSE_INVALID_MASK;
        }

        MouClearSemaphore(FC_MOUREGISTER);
      }
    }
  }

  #ifdef MMIOPH
    if (global_info->SIS_mec_table[SIS_MOUMEC] & MOU_TRACEMASK)
      MMIOMOUTrace(FC_MOUREGISTER, MOU_POSTBASE);
  #endif

  return(RC);
}

/******************* START OF SPECIFICATIONS ********************************/
/*                                                                          */
/*  SUBROUTINE NAME:  MouDeRegister  (not replaceable by MouRegister)       */
/*                                                                          */
/*  DESCRIPTIVE NAME:  Process MouDeRegister API.                           */
/*                                                                          */
/*  FUNCTION: Reset the ASCIIZ module name, procedure name, and the         */
/*            function mask for the current screen group.                   */
/*                                                                          */
/*  NOTES: If the process issuing a MOUDEREGISTER call is not the same      */
/*         process that successfully issued a MOUREGISTER call, it will     */
/*         receive an error return code.                                    */
/*                                                                          */
/*  ENTRY POINT:  MouDeRegister                                             */
/*      LINKAGE:  CALL FAR                                                  */
/*                                                                          */
/*  INPUT:  None                                                            */
/*                                                                          */
/*  EXIT-NORMAL:  RC = NO_ERROR                                             */
/*                                                                          */
/*  EXIT-ERROR: error code from SetSemaphore()                              */
/*           ERROR_MOUSE_DEREGISTER - Must be PID that called MouRegister   */
/*                                    and MouRegister must be have been     */
/*                                    successful for this Screen Group.     */
/*                                                                          */
/* INTERNAL REFERENCES:                                                     */
/*   INSTANCE data: none                                                    */
/*                                                                          */
/*     COMMON data: none                                                    */
/*                                                                          */
/*        ROUTINES: SetSemaphore() - Called to synchronize calls through    */
/*                               the Router and check for Full Screen,      */
/*                               screen group which is the only valid screen*/
/*                               group allowed to make these API calls.     */
/*                                                                          */
/* EXTERNAL REFERENCES:                                                     */
/*      ROUTINES: None                                                      */
/*                                                                          */
/******************* END  OF  SPECIFICATIONS ********************************/

USHORT APIENTRY _loadds _saveregs MOUDEREGISTER(VOID) {
  USHORT RC = NO_ERROR;

  #ifdef MMIOPH
    if (global_info->SIS_mec_table[SIS_MOUMEC] & MOU_TRACEMASK)
      MMIOMOUTrace(FC_MOUDEREGISTER,MOU_PREBASE);
  #endif

  if (CurrentSGID == PT_VIOPOPUP)
    RC = ERROR_MOUSE_DEREGISTER;
  else
    if (CurrentTYPE == LIS_PT_VIOWIN)
      RC = ERROR_MOUSE_DEREGISTER;

  if (RC == NO_ERROR) {
    RC = MouCheckProcType();
    if (RC == NO_ERROR) {
      RC = MouGetSemaphore(FC_MOUREGISTER);
      if (RC == NO_ERROR) {
        if (SGData->MOU_AMSCB != 0L) {
          /***********************************************************/
          /* Allow only owners PID or PID that started screen group. */
          /***********************************************************/
          if (SGData->MOU_AMSCB->PID == CurrentPID ||
              SGData->SGCB_PID == CurrentPID) {           /* 072823 */
            DosFreeModule(SGData->MOU_AMSCB->Handle);
            DOSSMFREEMEM((PALTCB)SGData->MOU_AMSCB);      /* B733730 */
            SGData->MOU_Mask = 0L;
            SGData->MOU_AMSCB = 0L;
            AMS_Addr = 0L;
          }
          else
            RC = ERROR_MOUSE_DEREGISTER;

        }
        else
          RC = ERROR_MOUSE_DEREGISTER;

        MouClearSemaphore(FC_MOUDEREGISTER);
      }
    }
  }

  #ifdef MMIOPH
    if (global_info->SIS_mec_table[SIS_MOUMEC] & MOU_TRACEMASK)
      MMIOMOUTrace(FC_MOUDEREGISTER,MOU_POSTBASE);
  #endif

  return(RC);
}

/*********************** START OF SPECIFICATIONS *****************************/
/*                                                                           */
/* SUBROUTINE NAME: MouInitReal        (Not replacable by MouRegister)       */
/*                                                                           */
/* DESCRIPTIVE NAME: This call does nothing because the change from 3x box   */
/*                   in 1.3 to MVDM's in 2.0 along with the addition of      */
/*                   VMOUSE.SYS, makes this call not needed.                 */
/*                                                                           */
/*  FUNCTION:  Session Manager called this to change the mode of the         */
/*             Pointer Draw Device Driver to real mode.                      */
/*                                                                           */
/* NOTES: none                                                               */
/*                                                                           */
/* ENTRY POINT: MouInitReal                                                  */
/*     LINKAGE: CALL FAR                                                     */
/*                                                                           */
/* INPUT: DriverName -  ASCIIZ Pointer Draw Device driver name               */
/*                                                                           */
/*  EXIT-NORMAL:  RC = NO_ERROR                                              */
/*                                                                           */
/*  EXIT-ERROR:  none                                                        */
/*                                                                           */
/* INTERNAL REFERENCES:                                                      */
/*   INSTANCE data: none                                                     */
/*   COMMON data:   none                                                     */
/*                                                                           */
/* EXTERNAL REFERENCES:                                                      */
/*   LOCAL info: none                                                        */
/*  GLOBAL info: none                                                        */
/*                                                                           */
/*********************** END OF SPECIFICATIONS *******************************/

USHORT APIENTRY _loadds _saveregs MOUINITREAL(PSZ DriverName) {
  USHORT RC = NO_ERROR;

  /********************************************************************/
  /* If called from Session Manager PID, NO-OP otherwise return error */
  /********************************************************************/
  if (CurrentPID != sesmgr_pid)
    RC = ERROR_MOUSE_SMG_ONLY;

  return(RC);
}

/*********************** START OF SPECIFICATIONS *****************************/
/*                                                                           */
/* SUBROUTINE NAME: KbdSynch           (Not replacable by KbdRegister)       */
/*                                                                           */
/* DESCRIPTIVE NAME: This call synchronizes access from a keyboard           */
/*                   subsystem to the keyboard device driver.                */
/*                                                                           */
/*  FUNCTION:  Blocks all other threads within the session until return      */
/*             from the subsystem if the API is KbdStringIn or KbdCharIn.    */
/*             A call to DosFSRamSemClear API is done in the                 */
/*             KbdClearSemaphore routine to release the semaphore            */
/*             accessed by this API.                                         */
/*                                                                           */
/* NOTES: none                                                               */
/*                                                                           */
/* ENTRY POINT: KbdSynch                                                     */
/*     LINKAGE: CALL FAR from Base Subsystem or Alternate Subsystem ONLY.    */
/*                                                                           */
/* INPUT: IOWait = is either Wait (-1L) or NoWait (0)                        */
/*                                                                           */
/*  EXIT-NORMAL:  RC = NO_ERROR                                              */
/*                                                                           */
/*  EXIT-ERROR:  none                                                        */
/*                                                                           */
/* INTERNAL REFERENCES:                                                      */
/*   INSTANCE data: none                                                     */
/*   COMMON data:   none                                                     */
/*                                                                           */
/* EXTERNAL REFERENCES:                                                      */
/*   LOCAL info: none                                                        */
/*  GLOBAL info: none                                                        */
/*                                                                           */
/*********************** END OF SPECIFICATIONS *******************************/

USHORT APIENTRY _loadds _saveregs KBDSYNCH(USHORT IOWait) {       /* B731619 */
USHORT RC = NO_ERROR;
SEL far *sync_callerCS;               /* Temporary pointer to callers CS  */
ULONG  WaitFlag;

  #ifdef MMIOPH
    if (global_info->SIS_mec_table[SIS_KBDMEC] & KBD_TRACEMASK)
      MMIOKBDTrace(FC_KBDSYNCH,KBD_PREBASE);
  #endif

  sync_callerCS = (SEL far *)&IOWait; /* Address next to callers CS       */
  sync_callerCS--;                    /* Adjust to point to callers CS    */

  /*********************************************/
  /* If callers segment equals the AKS segment. /
  /*********************************************/
  if ((FP_SEG(AKS_Addr) | RING3VAL) == *sync_callerCS) {

    if (IOWait == SEM_RETURN)
      WaitFlag = SEM_IMMEDIATE_RETURN;
    else if (IOWait == SEM_WAIT)
      WaitFlag = SEM_INDEFINITE_WAIT;
    else
      RC = ERROR_KBD_INVALID_IOWAIT;

    if (RC == NO_ERROR) {
      RC = KbdCheckProcType();
      if (RC == NO_ERROR) {
        RC = KbdGetSemaphore(WaitFlag);                     /* 059591 */
        if (RC == NO_ERROR)
          KbdClearSemaphore();
      }
    }
  }
  else
    RC = ERROR_KBD_EXTENDED_SG;

  #ifdef MMIOPH
    if (global_info->SIS_mec_table[SIS_KBDMEC] & KBD_TRACEMASK)
      MMIOKBDTrace(FC_KBDSYNCH,KBD_POSTBASE);
  #endif

  return(RC);
}

/*********************** START OF SPECIFICATIONS *****************************/
/*                                                                           */
/* SUBROUTINE NAME: MouSynch           (Not replacable by KbdRegister)       */
/*                                                                           */
/* DESCRIPTIVE NAME: This call synchronizes access from a mouse              */
/*                   subsystem to the mouse device driver.                   */
/*                                                                           */
/*  FUNCTION:  Blocks all other threads within the session until return      */
/*             from the subsystem if MouReadEventQue is the called API.      */
/*             A call to DosFSRamSemClear API is done in the                 */
/*             MouClearSemaphore routine to release the semaphore            */
/*             accessed by this API.                                         */
/*                                                                           */
/* NOTES: none                                                               */
/*                                                                           */
/* ENTRY POINT: MouSynch                                                     */
/*     LINKAGE: CALL FAR from Base Subsystem or Alternate Subsystem ONLY.    */
/*                                                                           */
/* INPUT: IOWait = is either Wait (-1L) or NoWait (0)                        */
/*                                                                           */
/*  EXIT-NORMAL:  RC = NO_ERROR                                              */
/*                                                                           */
/*  EXIT-ERROR:  none                                                        */
/*                                                                           */
/* INTERNAL REFERENCES:                                                      */
/*   INSTANCE data: none                                                     */
/*   COMMON data:   none                                                     */
/*                                                                           */
/* EXTERNAL REFERENCES:                                                      */
/*   LOCAL info: none                                                        */
/*  GLOBAL info: none                                                        */
/*                                                                           */
/*********************** END OF SPECIFICATIONS *******************************/

USHORT APIENTRY _loadds _saveregs MOUSYNCH(USHORT IOWait) {       /* B731619 */
USHORT RC = NO_ERROR;
SEL far *sync_callerCS;               /* Temporary pointer to caller's CS  */

  #ifdef MMIOPH
    if (global_info->SIS_mec_table[SIS_MOUMEC] & MOU_TRACEMASK)
      MMIOMOUTrace(FC_MOUSYNCH,MOU_PREBASE);
  #endif

  sync_callerCS = (SEL far *)&IOWait; /* Address next to caller's CS       */
  sync_callerCS--;                    /* Adjust to point to caller's CS    */

  /*********************************************/
  /* If callers segment equals the AMS segment. /
  /*********************************************/
  if ((FP_SEG(AMS_Addr) | RING3VAL) == *sync_callerCS) {
    RC = MouGetSemaphore(FC_MOUSYNCH);
    if (RC == NO_ERROR)
      MouClearSemaphore(FC_MOUSYNCH);
  }
  else
    RC = ERROR_MOU_EXTENDED_SG;

  #ifdef MMIOPH
    if (global_info->SIS_mec_table[SIS_MOUMEC] & MOU_TRACEMASK)
      MMIOMOUTrace(FC_MOUSYNCH,MOU_POSTBASE);
  #endif

  return(RC);
}

