
;/*************************************************************************
;*
;* SOURCE FILE NAME = IOSET.ASM
;*
;* DESCRIPTIVE NAME = Mouse Device Driver, Protect Mode IOCtls.
;*
;* COPYRIGHT    COPYRIGHT IBM CORPORATION, 1991, 1992
;*              Copyright Microsoft Corporation, 1990
;*              LICENSED MATERIAL - PROGRAM PROPERTY OF IBM
;*              REFER TO COPYRIGHT INSTRUCTION FORM#G120-2083
;*              RESTRICTED MATERIALS OF IBM
;*              IBM CONFIDENTIAL
;*
;* VERSION      V2.0
;*
;* DATE         01/23/92
;*
;* DESCRIPTION  Mouse Device Driver, Protect Mode IOCtls.
;*
;* FUNCTIONS    IOMW_MM   (Cat 0Ah, Function 40h)
;*              SGControl (Cat B - function 41h)
;*              IOMW_SM    (51h)
;*              IOMW_SS    (53h)
;*              IOMW_EM    (54h)
;*              IOMW_TH    (55H)
;*              IOMW_PS    (56h)
;*              IOMW_DP    (57h)
;*              IOMW_RP    (58h)
;*              IOMW_SP    (59h)
;*              IOMW_SD    (5A)
;*              IOMW_DS    (5C)
;*              IOMW_MD    (5Dh)
;*
;* NOTES        This file contains Mouse DD Protect Mode IOCtl
;*              Set worker routines.
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   01/23/92  @V2.0XXX01  B736749
;*
;*   09/11/95  @131957     131957 Constrained mouse pointer
;**************************************************************************


.386p

INCL_WINPROGRAMLIST    equ          1      ; define for pmshl.inc defines
INCL_ERRORS            equ          1      ; define for pmshl.inc defines
SESMGR                 equ          1      ; define for pmshl.inc defines


.xlist
        include mouse.inc
        include singleq.inc
        include pmshl.inc
        include basemaca.inc
        include osmaca.inc
.list

CPUMODE 386

;*
;*    External Mouse Module Data References
;*
       extrn  Num_Grps             : byte
       extrn  CallSessn            : byte
       extrn  FgndSessn            : byte
       extrn  Modes                : byte
       extrn  DeviceData           : byte
       extrn  DDD                  : byte
       extrn  SQDDName             : byte
       extrn  SQDD                 : byte
       extrn  Detach_Proc          : byte
       extrn  Ptr_Overide          : byte
       extrn  SN_Flags             : byte
       extrn  Ptr_Rec              : byte

       extrn  Sem_PID              : word
       extrn  Eq_Length            : word
       extrn  CallPID              : word
       extrn  SQ_Pid               : word
       extrn  VDM_Flags            : word
       extrn  EMaskMax             : word

       extrn  Device_Help          : dword
       extrn  FgndCB               : dword

       extrn  FlushMonChain        : near
       extrn  GetExtModeData       : near
       extrn  PtrDrawCheck         : near
       extrn  Monitor_Handler      : near
       extrn  AllocCB              : near
       extrn  EnableMouse          : near
       extrn  DisableMouse         : near
       extrn  InitFSCB             : near
       extrn  FindCB               : near
       extrn  FreeCB               : near
       extrn  SGSwitchStart        : near
       extrn  SGSwitchEnd          : near
       extrn  SGCreate             : near
       extrn  SaveCfgData          : near
       extrn  GetCfgDataOffset     : near
       extrn  SaveExtModeData      : near

       extrn  Emi_BegVMChange      : near                        ;emi
       extrn  Emi_EndVMChange      : near                        ;emi
       extrn  Emi_BegSesSwitch     : near                        ;emi
       extrn  Emi_EndSesSwitch     : near                        ;emi

       extrn  DrawPointer          : far
       extrn  RemovePointer        : far

       EXTRNFAR Calc_Num

CSEG   SEGMENT   WORD  PUBLIC  USE16 'CODE'
CSEG   ENDS

CSEG2   SEGMENT  WORD  PUBLIC  USE16  'SWAPCODE'
        ASSUME    CS:CSEG2, SS:NOTHING, ES:NOTHING, DS:NOTHING

;*
;*    Module Procs made Public for other Mouse Modules
;*


       public  IOMW_MM       ; Cat A - func 40h
       public  SGControl     ; Cat B - func 41h

       public  IOMW_SM       ; Cat 7 - func 51h
       public  IOMW_SS       ; Cat 7 - func 53h
       public  IOMW_EM       ; Cat 7 - func 54h
       public  IOMW_TH       ; Cat 7 - func 55h
       public  IOMW_PS       ; Cat 7 - func 56h
       public  IOMW_DP       ; Cat 7 - func 57h
       public  IOMW_RP       ; Cat 7 - func 58h
       public  IOMW_SP       ; Cat 7 - func 59h

       public  IOMW_SD       ; Cat 7 - func 5ah
       public  IOMW_DS       ; Cat 7 - func 5ch
       public  IOMW_MD       ; Cat 7 - func 5dh
       public  IOMW_RG       ; Cat 7 - func 5eh (GRADD)
       public  IOMW_CS       ; Cat 7 - func 6ch


;**********************************************************************
;*
;*  FUNCTION NAME :  IOMW_MM   (Cat 0Ah, Function 40h)
;*
;*  DESCRIPTION   :  Performs Mouse Monitor Registration
;*                   for a Generic IOCtl request block that
;*                   is generated by a DosMonReg function
;*                   call.
;*
;*                   The data address field points to a monitor
;*                   register packet.  This packet has four fields:
;*                      1. word  - placement in the chain.
;*                      2. word  - index field.
;*                      3. dword - address of input buffer.
;*                      4. word  - offset to ouput buffer.
;*                   A DevHlp is used to add the monitor to the
;*                   requested session's chain.
;*
;*  ENTRY POINT   :  IOMW_MM           LINKAGE:  CALL NEAR
;*
;*  INPUT         :  ES:BX points to the request block.
;*                   DS:SI has offset to current session control block
;*                   FS    Mouse data selector
;*
;*  NOTES         :  A detached process cannot register a monitor for
;*                  its own session. It can however register a monitor
;*                  for a different session, as long as that session
;*                  is a valid full screen session.
;*
;*  RETURN-NORMAL :  Monitor is added to caller's session monitor
;*                   chain.
;*
;*  RETURN-ERROR  :  Error code set in Request Block status field.
;*
;*  EFFECTS       :  Stack is clean on return.  Regs not preserved.
;*
;*  INTERNAL REFERENCES:
;*           ROUTINES:   NONE.
;*
;*  EXTERNAL REFERENCES:
;*           ROUTINES:  NONE.
;*           DevHlps:   Register.
;*
;**********************************************************************
;* PSEUDOCODE :
;*
;* BeginSub  IOMW_MM  (register a mouse monitor)
;*
;* get user register parameters
;* disable system ints
;* get requested session number
;* IF <current process is DETACHED  AND
;*     request is for current session>
;*    set requested session to Max_Session to cause failure
;* ENDIF
;* IF <requested session is gt -1 AND
;*     lt Max_Session>
;*    IF <specific session requested>
;*       get MSCB of requested session
;*    ENDIF
;*    IF <monitor session does not have SQ mode active>
;*       call Device_Help(Register) to register the monitor
;*       IF <Register worked>
;*          increment session monitor chain size
;*       ELSE
;*          set General Failure error code
;*       ENDIF
;*    ELSE
;*       set parameter error
;*    ENDIF
;* ELSE
;*    set parameter error
;* ENDIF
;* enable system ints
;* return
;*
;* EndSub  IOMW_MM
;*
;************************************************************************


IOMW_MM  PROC  near

TempES     equ   <(word ptr [bp-2])>   ; Request packet selector
TempBX     equ   <(word ptr [bp-4])>   ; Reguest packet offset
TempSI     equ   <(word ptr [bp-6])>   ; CB offset of foreground session
TempDS     equ   <(word ptr [bp-8])>   ; CB selector of foreground session
OtherSI    equ   <(word ptr [bp-10])>  ; CB offset of SG to be monitored
OtherDS    equ   <(word ptr [bp-12])>  ; CB selector of SG to be monitored
ErrorCode  equ   <(word ptr [bp-14])>  ; 0 = no error, other is error code

   Enter  14,0

   mov  TempES, es                     ; Save RP selector
   mov  TempBX, bx                     ; Save RP offset
   mov  TempSI, si                     ; Save foreground SG CB Offset
   mov  TempDS, ds                     ; Save foreground SG CB Selector
   mov  OtherSI, si                    ; Init to current SGs CB Offset
   mov  OtherDS, ds                    ; Init to current SGs CB Selector
   mov  ErrorCode, 0

   les  bx, es:[bx].GIODataPack         ; Get Addr of Data Packet
   cli                                  ; Disable interrupts for Mon register
   mov  ax, es:[bx].Index               ; Get Requested SG for MonChain

   .if <ax eq -1>                       ; If current SG ID

      .if <fs:Detach_Proc eq ON> OR     ; If this is a detached proc (OR)
      .if <bit [si].D_Status nz SQ_Mode>; If we are in the PM SG
         mov  ErrorCode, MNS            ; then no_monitor_support
      .endif

   .else                                ; Caller specificed a SG #

      .if <ax lt -1> OR                 ; If Index is less then -1 (OR)
      .if <ah gt 0> OR                  ; If high byte is not 0 (OR)
      .if <al ge fs:Num_Grps>           ; if Index is greater= 16
         mov  ErrorCode, INVALIDPARMS   ; then caller has invalid parms

      .elseif <ax eq 2>                 ; Old 3X box SG # then return
         mov  ErrorCode, MNS            ; error no_monitor_support

;*
;*      @V2.OXXXO1- We should check the calling session (CallSessn)
;*      instead of foreground session (FgndSession) because the application
;*      can call from a background or detached process.
;*

;**     .elseif <al ne fs:FgndSessn>      ; Index valid and not fgnd
      .elseif <al ne fs:CallSessn>      ; Index valid and not fgnd

;*
;*        At this point we know that we are about to register a
;*        monitor for a session that is not in the foreground. If
;*        this session has not been created yet we must create the CB
;*        for this screen group.
;*

         mov  bl, al                    ; get session #
         xor  bh, bh
         push fs
         pop  ds
         call FindCB                    ; ds:si -> CB if created already

         .if <c>                        ; if not found, create the CB
            mov  cx, SIZE ScrGp_Data    ; size of the full screen CB
            add  cx, Eq_Length          ; add on event queue size
            call AllocCB                ; returns ds:si -> new CB allocated
            .if <c>
               mov  ErrorCode, GENERALFAILURE
            .else
               call InitFSCB
            .endif
         .endif

         mov OtherDS, ds                ; Sel of the CB to be monitored
         mov OtherSI, si                ; Off of the CB to be monitored

      .endif

;*
;*      DCAF CHANGE - We should check the SQ_Mode flag instead of
;*      Shell_Session when the application is trying to register a
;*      monitor. DCAF temporarily disables the singleq before registering
;*      a monitor for screen group 1.
;*
;**   .elseif <ax eq Shell_Session> OR  ; Else if Index equals PM SG (OR)
      .if <bit [si].D_Status nz SQ_Mode>
         mov  ErrorCode, MNS            ; error no_monitor_support
      .endif


   .endif


;*
;* At this point DS:SI points to the CB for the requested screen group ID
;*

;*
;* If no errors where encountered we will create the monitor chain if
;* this hasn't been done yet.
;*

   .if <ErrorCode eq 0>

      mov  al, [si].Chain_Size               ; # of Monitors in chain
      .if <al eq 0>                          ; If none so far
                                             ; Create the Monitor chain
         mov  [si].MB_Len, 14                ; This must always be set
         add  si, MB_Len                     ; add in offset to MOB
         mov  es, OtherDS                    ; SG CB selector
         push cs
         pop  ds                             ; Notify Rtn Address
         mov  di, offset Monitor_Handler
         xor  ax, ax                         ; Specify Create Chain
         mov  dl, DevHlp_MonitorCreate       ; Specify function num
         call fs:Device_Help                 ; Invoke MonitorCreate
         mov  si, OtherSI                    ; Restore CB offset
         mov  ds, OtherDS                    ; Restore CB selector

         .if <nc>
            mov  [si].Chain_Hdle, ax         ; Store handle returned
         .else
            mov  ErrorCode, GENERALFAILURE
         .endif

      .endif

   .endif

   .if <ErrorCode eq 0>

      mov  cx, fs:Sem_PID                     ; Get caller's PID
      mov  ax, [si].Chain_Hdle                ; Load SG Mon Chain Handle
      mov  es, TempES                         ; Restore RP selector
      mov  bx, TempBX                         ; Restore RP offset
      les  bx, es:[bx].GIODataPack            ; Access Data Parm Record
      mov  dh, byte ptr es:[bx].P_Flag        ; Get placement flag
      mov  dl, DevHlp_Register                ; Register function
      mov  di, es:[bx].Output_Buff            ; Load Output Buf Offset
      mov  si, word ptr ES:[BX].Input_Buff    ; Load Input Buf Offset
      mov  es, word ptr ES:[BX].Input_Buff[2] ; Load Input Buf Selector
      call fs:Device_Help                     ; do the register
      mov  si, OtherSI

       .IF nc                         ; Normal return from Register?
         inc  [SI].Chain_Size         ; Update monitor chain counter
       .ELSE
         mov  ErrorCode, GENERALFAILURE
       .ENDIF

   .endif

   mov  es, TempES
   mov  bx, TempBX
   mov  si, TempSI
   mov  ds, TempDS

   .if <ErrorCode ne 0>
      mov  ax, ErrorCode
      mov  es:[bx].PktStatus, ax
   .endif

   sti                              ; Enable interrupts DevHlp Complete
   Leave                            ; Clear local vars off stack
   ret                              ; Return to Request Handler Rtn

IOMW_MM  ENDP

;**********************************************************************
;*
;* FUNCTION NAME  : SGControl (Cat B - function 41h)
;*
;* DESCRIPTION    : This routine handles all notifications that we
;*                  registered for with the session manager via the
;*                  DOSSMREGISTERDD call at init time.
;*
;* ENTRY POINT    : SGControl        LINKAGE: CALL NEAR
;*
;* INPUT          : ES:BX -> request packet
;*                  FS,DS -> mouse data segment
;*
;*                  The parameter packet has the following format
;*
;*                  SC_Length  - WORD   - Varies according to action
;*                  SC_Action  - WORD   - Could be any action below
;*                  SC_Data    - BYTES  - Varies according to action
;*
;*                  If action is          The data is
;*
;*                  08h   TERMINATION        TN_TypeOut   - WORD
;*                                           TN_SIDOut    - WORD
;*
;*
;*                  10h   CREATION           CN_SIDIn     - WORD
;*                                           CN_TypeIn    - WORD
;*
;*                  20h   PRESWITCH OR       PS_SIDIn     - WORD
;*                  40h   POSTSWITCH         PS_TypeIn    - WORD
;*                                           PS_SIDOut    - WORD
;*                                           PS_TypeOut   - WORD
;*
;*
;*                 100h   AIMPOSTSAVE        AIM_Errors   - DWORD
;*                                           AIM_Active   - WORD
;*                                           AIM_TimeOut  - WORD
;*                                           AIM_FKAccept - DWORD
;*                                           AIM_FKRate   - DWORD
;*                                           AIM_FKDelay  - DWORD
;*
;* RETURN-NORMAL  : Always
;*
;*                  Carry Flag clear
;*                  ES:BX preserved
;*                  All other registers are undefined
;*
;* EFFECTS        : Registers modified
;*
;* INTERNAL REFERENCES:
;*    ROUTINES: SGSwitchStart, SGSwitchEnd, FreeCB, SGCreate
;*
;* EXTERNAL REFERENCES:
;*    ROUTINES: None
;*    DEVHLPS:  None
;*
;**********************************************************************
;*
;* PSEUDOCODE :
;*
;* BeginSub  SGControl
;*
;*      Save the request packet pointer.
;*      Load a pointer to the parameter packet
;*
;*      IF <Action eq PRESWITCH>
;*         IF <Outgoing Type eq PROG_FULLSCREEN>
;*            Get SG number going out.
;*            call SGSwitchStart to initiate the SG switch
;*         ELSE
;*            Do nothing
;*         ENDIF
;*
;*
;*      ELSEIF <Action eq POSTSWITCH>
;*         IF <Incoming Type eq PROG_FULLSCREEN>
;*            Get SG number coming in.
;*            call SGSwitchEnd to end the SG switch
;*         ELSE
;*            Clear carry, no error ignored operation
;*            Zero pointer to fgnd CB
;*            Shut down processing mouse data
;*            Get SG number coming in.
;*         .endif
;*
;*         Store fgndsessn
;*
;*
;*      ELSEIF <Action eq TERMINATION>
;*         IF <Outgoing Type eq PROG_FULLSCREEN>
;*            Get Outgoing SGID
;*            IF <SGID eq FgndSessn>
;*               Zero out pointer to foreground CB
;*               Shut down processing data
;*            ENDIF
;*            Get CB for this SG
;*            IF <no monitors registered>
;*               call FreeCB to de-allocate to memory for the CB
;*            ENDIF
;*         ELSEIF <Outgoing Type eq PROG_VDM>
;*            AND off VDMREADY bit to stop sending events to VMSE
;*         ELSE
;*            clear carry and ignore operation
;*         ENDIF
;*
;*
;*      ELSEIF <Action eq CREATION>
;*         IF <Incoming type eq PROG_FULLSCREEN>
;*            get incoming SG number
;*            call SGCreate to allocate memory for the CB
;*         ELSEIF <Incoming Type eq PROG_VDM>
;*            AND off VDMREADY (VMSE is not ready for events yet)
;*         ELSE
;*            clear carry and ignore operation
;*         ENDIF
;*         ENDIF
;*
;*      ELSEIF <Action eq AIMPOSTSAVE>
;*         IF <AIM_Active eq 0>
;*            Turn off SN_ACTIVE bit in SN_Flags byte
;*         ELSE
;*            Turn on SN_ACTIVE bit in SN_Flags byte
;*         ENDIF
;*
;*      ELSE
;*         Clear carry (operation is ignored)
;*      ENDIF
;*
;*      Point ES:BX back to RP
;*      return
;*
;*
;* EndSub  SGControl
;*
;************************************************************************

public SGControl ;whswhs deleteme
SGControl  proc  near

       ?frame = 0                         ; Get Local/Temp Stack Frame
       LocalVar TempES, WORD              ; For ES register
       LocalVar TempBX, WORD              ; For BX register
       LocalVar TempDS, WORD              ; For DS register

       EnterProc

;*
;*      First save the request packet pointer.  Then get the pointer to the
;*      switch control input.
;*

       mov  TempES, es
       mov  TempBX, bx
       mov  TempDS, ds

       les  bx, es:[bx].GIOParaPack

;*
;*      If it is a PRESWITCH operation then get the current screen group
;*      number.  If it is a fullscreen session then start a switch.  If not
;*      a fullscreen clear the carry flag to show no error (operation ignored).
;*      In both cases the call may return an error, if so the carry flag is
;*      propagated to the end of the routine and returned to the caller
;*

       .if <es:[bx].SC_Action eq PRESWITCH>
          mov  cx, es:[bx].PS_SIDIn                                   ;emi
          .if <es:[bx].PS_TypeOut eq PROG_FULLSCREEN>
             mov  bx, es:[bx].PS_SIDOut                               ;emi
             mov  ax, TRUE                                            ;emi
             push bx
             call Emi_BegSesSwitch ; cx = caller's session            ;emi
                                   ; bx = future   session            ;emi
             pop  bx               ; ax = TRUE = fullscreen           ;emi
             call SGSwitchStart
          .else
             mov  bx, es:[bx].PS_SIDOut                                ;emi
             mov  ax, FALSE                                            ;emi
             call Emi_BegSesSwitch ; cx = caller's session             ;emi
                                   ; bx = future   session             ;emi
                                   ; ax = FALSE = not full screen      ;emi
             clc
          .endif

;*
;*      Now see if this is a POSTSWITCH operation.  This operation is done
;*      after the switch is complete.  The SC_Incomming field is the new
;*      screen group that is in the foreground.  If the new screen group is
;*      not a recognized type then the foreground control block pointer is
;*      zero'd so that no one will try to access it.  In all cases store the
;*      new foreground session number.
;*

       .elseif <es:[bx].SC_Action eq POSTSWITCH>
          .if <es:[bx].PS_TypeIn eq PROG_FULLSCREEN>
             mov  bx, es:[bx].PS_SIDIn      ; get affected session
             mov  ax, TRUE                                              ;emi
             push bx                                                    ;emi
             call Emi_EndSesSwitch ; bx = session                       ;emi
                                   ; ax = TRUE = fullscreen             ;emi
             pop  bx                                                    ;emi
             call SGSwitchEnd               ; end a screen group switch
          .else                             ; Other session type
             mov  word ptr FgndCB+2, 0      ; zero pointer
             mov  Ptr_Overide, ON           ; shut down processing mouse data
             mov  bx, es:[bx].PS_SIDIn      ; get affected session
             mov  ax, FALSE                                               ;emi
             call Emi_EndSesSwitch          ; bx = session                ;emi
                                            ; ax = FALSE = not full screen;emi
             clc                            ; no error, ignored operation ;emi
          .endif
          mov  fs:FgndSessn, bl

;*
;*      If the operation is a TERMINATION, then the SC_Current field has the
;*      session number that is being terminated.  If the session type is
;*      supported then we go get the CB pointer.  If the session has no
;*      monitors in its chain then the CB is freed by calling FreeCB, otherwise
;*      some process in another session has registered a monitor in this
;*      session.  The CB remains so that when the session is created again the
;*      monitor will be present.
;*

       .elseif <es:[bx].SC_Action eq TERMINATION>
          .if <es:[bx].TN_TypeOut eq PROG_FULLSCREEN>
             mov  bx, es:[bx].TN_SIDOut
             .if <bl eq FgndSessn>                ; If the session is the
                mov  word ptr FgndCB+2, 0         ; foreground then zero ptr.
                mov  Ptr_Overide, ON              ; shut down processing data
             .endif
             call FindCB                          ; Get the current ptr.
             .if <[si].Chain_Size eq 0>           ; monitors registered
                mov  ds, TempDS                   ; Re-load base DS
                call FreeCB                       ; then free the CB
             .endif
          .else
             clc
          .endif

;*
;*      If operation is a CREATION, then SC_Incomming is the new session
;*      number.  If it is a full screen session type then check to see if
;*      the CB has already been allocated. The only way that a CB could
;*      already be allocated before this CREATION notification is if an
;*      app has already registered a monitor for this new SG ID.
;*
;*      If the the TypeIn is a VDM the simply init the VDMREADY bit and
;*      and return.
;*
;*      All CREATION notifications for other SG types are ignored.
;*

       .elseif <es:[bx].SC_Action eq CREATION>
          .if <es:[bx].CN_TypeIn eq PROG_FULLSCREEN>
             mov  bx, es:[bx].CN_SIDIn
             call FindCB                         ; Check if CB already alloced
             .if <c>                             ; If not
                call SGCreate                    ; Alloc CB
             .endif
          .else
             clc
          .endif

;*
;*      If operation is a AIMPOSTSAVE check the AIM_Active word of the
;*      parameter packet. If upported session type then call SGCreate to
;*      create the control block.
;*

       .elseif <es:[bx].SC_Action eq AIMPOSTSAVE>
          .if <es:[bx].AIM_Active eq 0>
             and SN_Flags, NOT SNF_ACTIVE
          .else
             or SN_Flags, SNF_ACTIVE
          .endif
;*
;*      Otherwise the operation is not recognized.  The carry flag is left
;*      clear to show the operation is not an error.  It is ignored.
;*

       .else
          clc
       .endif

       mov  bx, TempBX       ; restore request packet address
       mov  es, TempES
       LeaveProc
       ret

SGControl  Endp


;**********************************************************************
;*
;*  FUNCTION NAME :  IOMW_SM    (51h)
;*
;*  DESCRIPTION   :  Performs the Mouse IOCtl function
;*                     IOMW_SM, start a display mode change.
;*
;*                  The parameter list field points to a VIOSetMode
;*                  record.  The data list field points to the
;*                  displays configuration data.  If the current
;*                  session is in the FG and the set mode window flag
;*                  is not set then the pointer is hidden.  This is
;*                  maintain compatibility with old mouse subsystems.
;*                  The set mode window flag is always set if the
;*                  mode data is valid.  The flag may have been set
;*                  by the ptr draw register IOCtl.  The Pointer
;*                  Draw DD is then called to validate the new mode
;*                  data.  If supported then Point DD will fill in
;*                  the session control block with the mode data.
;*                  If unsupported then mouse support for that session
;*                  is disabled.  IOCtl IOMW_MD is used to finish the
;*                  mode switch.  Status word on stack is used to
;*                  flag intermediate errors so processing can be
;*                  halted.  0 indicates no errors.
;*
;*  ENTRY POINT   : IOMW_SM         LINKAGE: CALL NEAR
;*
;*  INPUT         :  ES:BX points to the request block.
;*                   DS:SI has offset to current session control block.
;*
;*  RETURN-NORMAL :  Mouse pointer is hidden, session control block
;*                   mode data fields are updated.
;*
;*  RETURN-ERROR  :  session CB fields unchanged.  Device status
;*                   flags set to indicate mode unsupported.  Ptr
;*                   Draw functions are disabled until a supported
;*                   mode is set.
;*
;*  EFFECTS       :  Stack is clean on return.  Regs not preserved.
;*
;*  INTERNAL REFERENCES:
;*     ROUTINES   :  Calc_Num,     SaveCfgData, SaveExtModeData,
;*                   GetCfgDataOffset, CheckAccess
;*
;*  EXTERNAL REFERENCES:
;*     ROUTINES   :  Ptr Draw(RemovePointer, CheckModeProtect)
;*                DDDD(Enable_Device, Disable_Device)
;*     DevHelps:  NONE.
;*
;**********************************************************************
;* PSEUDOCODE :
;*
;* BeginSub  IOMW_SM  (set display mode)
;*
;* call DDDD(Disable_Device) to disable the mouse
;* IF <setmode window is not active>
;*    remove the pointer if needed
;*    set setmode window as active
;* ENDIF
;* IF <selector to config data is not NULL>
;*    IF <length of config data is valid>
;*       call SaveCfgData to save the config data
;*       IF <error saving config data>
;*          set error status
;*       ENDIF
;*       IF <status indicates no error so far>
;*          call GetCfgDataOffset to get config data offset
;*          IF <offset returned>
;*             store selector:offset in MSCB
;*          ELSE
;*             0 out sel:off in MSCB to show no cfg data available
;*          ENDIF
;*       ENDIF
;*    ENDIF
;* ENDIF
;*
;* IF <status indicates no errors so far>
;*    IF <current mode data available AND
;*        mode is supported>
;*       set flag indicating previous mode data exists
;*       save current display mode type resolutions
;*    ENDIF
;*    call PtrDraw(CheckModeProt) to check new display mode
;*
;*    IF <new display mode is supported>
;*       set device status to supported display mode
;*       IF <previous mode data exists>
;*          map old ptr position to new screen resolution
;*       ELSE
;*          set ptr position to center of screen
;*       ENDIF
;*    ELSE
;*       set parameter error (display mode not supported)
;*    ENDIF
;* ENDIF
;*
;* call DDDD(Enbale_Device) to enable the mouse
;*
;* return
;*
;* EndSub  IOMW_SM
;*
;************************************************************************

IOMW_SM  proc  near

TempES        equ  <(word ptr [bp-2])>     ; For ES register
TempBX        equ  <(word ptr [bp-4])>     ; For BX register
TempSI        equ  <(word ptr [bp-6])>     ; for SI register
Old_Col_Res   equ  <(word ptr [bp-8])>     ; for old mode data
Old_Row_Res   equ  <(word ptr [bp-10])>    ; for old mode data
Status        equ  <(word ptr [bp-12])>    ; For error status

;*
;* These equates are use for the status word.
;*

SM_ERROR      equ    1                    ; error detected
SM_PREVMODE   equ    2                    ; previous mode data was available

       Enter  12,0
       mov  TempES, es                    ; Save Request Block Address
       mov  TempBX, bx
       mov  TempSI, si                    ; save session CB offset
       mov  Status, 0                     ; no error so far

       call DisableMouse                  ; Hold Mouse Interrupts

       test [si].Ptr_Flags, SM_WinFlag    ; see if set mode window active now
       .if z                              ; if not then we must handle the
          mov  bl, fs:FgndSessn           ; compatibility case. FG session
          call PtrDrawCheck
          .IF <ax eq 0>                   ; If Not a Ptr Collision
             mov  al, fs:CallSessn        ; set foregrnd session
             push cx                      ; Save current reg value
             mov  cx, 0                   ; Flag Remove Ptr Required
             call RemovePointer           ; Hide Mouse Pointer Image
             pop  cx                      ; restore cx
          .endif                          ; Collision Area Test
          or  [si].Ptr_Flags, SM_WinFlag  ; set mode window active
       .endif
       mov  bx, TempBX                    ; restore offset to packet

;*
;* Check access to set mode data and config data.  We must be able to access
;* the mode data.  If we cannot access the config data it is not an error from
;* the mouse's view.  The config data address is passed in  session CB to ptr
;* draw.  If config data does not exist then this field is zero'd out. If ptr
;* draw needs to access the config data then he must return an error on the
;* check mode call.
;*

       test word ptr es:[bx].GIODataPack+2, 0fff8h
       .if <nz>                               ; valid selector(area valid)
          les  di, es:[bx].GIODataPack

          .if <<word ptr es:[di]> ae 14>
                                              ; looks like valid data
             mov  bx, es:[di]+CfgNumOff       ; get this config data's number
             push ds
             push es                          ; save cfg data selector
             mov  si, di                      ; put cfg data offset in si
             pop  ds                          ; DS:SI -> new config data
             call SaveCfgData                 ; try to save the config data
             pop  ds
             mov  si, TempSI                  ; restore session CB offset

             .if <c>                          ; if an error saving data
                or   Status, SM_ERROR         ; set error code
             .else                            ;
                call GetCfgDataOffset         ; get offset to config data
                .if <nc>                      ; offset of cfg data returned
                   mov  [si].CfgSelector, fs  ; save sel to config data
                   mov  [si].CfgOffset, dx    ; save offset fo config data
                .else                         ; error retrieveing offset
                   mov  [si].CfgSelector, 0   ; zero out he config data
                   mov  [si].CfgOffset, 0     ; pointer in the session CB
                .endif                        ; end cfg offset returned test
             .endif
          .endif
       .endif

;*
;* Config data has been stored, if given, and the session CB has been set up
;* to point to it.  Now if there were no previous errors then continue.
;* First set up the address to the mode data.  Then call ptr draw.
;*

       test Status, SM_ERROR                  ; Is everything cool so far?
       .if <z>  NEAR                          ; yes so continue
          mov  es, TempES                     ; restore packet selector
          mov  bx, TempBX                     ; and packet offset
          les  di, es:[bx].GIOParaPack        ; get mode data pointer

;*
;* We are now set up to call pointer draw to check the mode data.  Ptr draw
;* should only validate the mode data.  We sill save the mode data.
;* Save the extended mode data before calling ptr draw.  This is to avoid
;* having to reload addresses in case ptr draw destroys them.
;*

          .if <[si].MLength ne 0>  AND         ; Is there current mode data?
          test [si].D_Status, USS_Mode         ; and is it supported ? if so
          .if <z>                              ; then remap old position
             or   Status, SM_PREVMODE          ; Set previous mode flag
             test [si].MType, Graphics         ; Is mode a graphics mode ?
             .if <nz>                          ; If so then save the
                mov  ax, [si].GRow_Res         ; graphics row and column
                mov  bx, [si].GCol_Res         ; resolutions.
             .else                             ; Else it's a text mode so
                mov  ax, [si].TRow_Res         ; save the text row and
                mov  bx, [si].TCol_Res         ; column resolutions
             .endif                            ; end mode type test
             mov  Old_Row_Res, ax              ; Save old resolutions in
             mov  Old_Col_Res, bx              ; the save area
          .endif                               ; end mode data available test

          push es                              ; save mode data address
          push di                              ;

          mov  al, fs:CallSessn                ; calling session
          CheckModeProtect                     ; call ptr draw

          pop  di                              ; restore set mode address
          pop  es

          .if <ax eq 0>                        ; if mode supported
             and  [si].D_Status, NOT USS_Mode  ; Reset Disp Mode Flag Bit

;*
;* This section will if center the pointer if no previous mode data was
;* available, or map the old position to the new mode if there was old mode data.
;*

             test Status, SM_PREVMODE          ; was there old mode data
             .if <nz>                          ; yes so map old to new
                test es:[di].M_Type, Graphics     ; is new mode graphics ?
                .if <nz>                          ; yes
                   mov  bx, es:[di].New_GRow_Res  ; so get the graphics
                   push es:[di].New_GCol_Res      ; resolutions
                .else                             ; else text mode
                   mov  bx, es:[di].New_TRow_Res  ; so get the text
                   push es:[di].New_TCol_Res      ; resolutions
                .endif                            ; end mode type tests

                mov  ax, [si].Ptr_Row_Pos         ; current row position
                mov  cx, Old_Row_Res              ; old row resolution
                CALLFAR Calc_Num                  ; map to new
                mov  [si].Ptr_Row_Pos, ax         ; store new row position

                pop  bx                           ; get new col resolution
                mov  ax, [si].Ptr_Col_Pos         ; current col position
                mov  cx, Old_Col_Res              ; old col resolution
                CALLFAR Calc_Num                  ; map to new
                mov  [si].Ptr_Col_Pos, ax         ; store new col position

             .else

                test   es:[di].M_Type, Graphics   ; Check current Disp Mode
                .if nz                            ; If in Graphics Mode then
                   mov  ax, es:[di].New_GRow_Res  ; Get row resolution
                   mov  bx, es:[di].New_GCol_Res  ; Get col resolution
                .else                             ; If in Text Mode then
                   mov  ax, es:[di].New_TRow_Res  ; Get row resolution
                   mov  bx, es:[di].New_TCol_Res  ; Get col resolution
                .endif                            ; Display Mode Tests

                shr  ax, 1                        ; Get half row resolution
                mov  [si].Ptr_Row_Pos, ax         ; to center ptr position
                shr  bx, 1                        ; Get half col resolution
                mov  [si].Ptr_Col_Pos, bx         ; to center ptr position
             .endif
             xor  ch, ch                                                  ;emi
             mov  cl, fs:CallSessn                                        ;emi
             xor  bh, bh                                                  ;emi
             mov  bl, fs:FgndSessn                                        ;emi
             push si                                                      ;emi
             call Emi_BegVMChange              ; cx = caller's session    ;emi
                                               ; bx = future   session    ;emi
                                               ; es:di = video data       ;emi
                                                                          ;emi
             pop  si                                                      ;emi
          .else                                ; new Mode is not supported
             ParmErr
             or   [si].D_Status, USS_Mode      ; Set Unsupported Mode Bit
          .endif                               ; end supported mode test
       .else                                   ; intermediate error det.
          ParmErr                              ; set parameter error
          or   [si].D_Status, USS_Mode         ; Set Unsupported Mode Bit
       .endif                                  ; end error detection

;*
;* Now copy the base mode data to the session CB, regardless of return code.
;* Access to mode data is OK here.  1st load address to mode data.
;*

       mov  es, TempES                      ; restore sel to req packet
       mov  bx, TempBX                      ; restore off to req packet
       les  di, es:[bx].GIOParaPack         ; get ptr to mode data
       add  si, MLength                     ; pt to mode data fields
       mov  cx, BaseModeLen                 ; move only base mode data
       mov  al, fs:CallSessn                ; current session
       xor  ah, ah                          ; convert to word
       push ds                              ; exchange es and ds
       push es                              ;  ds -> mode data
       pop  ds                              ;  es -> our data seg
       pop  es                              ;
       xchg si, di                          ; switch si and di
       push ds:[si]                         ; save length of mode data
       cld                                  ; go forward
       rep  movsb                           ; copy the mode data
       pop  cx                              ; get saved mode data len
       sub  cx, BaseModeLen                 ; calc ext mode data len
       .if <cx gt 0>                        ; if there is ext mode data
          call SaveExtModeData              ; save the ext mode data
       .endif
       push es                              ; mouse cb from es
       pop  ds
       mov  si, TempSI                      ; restore session CB off

ifdef RESETCONSTRONSWITCH
       xor  ax,ax
       mov  [si].ConstrX0,ax
       mov  [si].ConstrY0,ax
       mov  ax,[si].GRow_Res
       mov  [si].ConstrY1,ax
       mov  ax,[si].GCol_Res
       mov  [si].ConstrX1,ax
endif

       call EnableMouse                    ; allow mouse interrupts

       mov  es, TempES                     ; Restore request packet address
       mov  bx, TempBX                     ; in es:bx

       Leave                               ; Clear Local Var Stack Frame

       ret                                 ; Return to IOCtl Handler Rtn
IOMW_SM  ENDP


;**********************************************************************
;*
;*  FUNCTION NAME :  IOMW_SS    (53h)
;*
;*  DESCRIPTION   :  Performs the Mouse IOCtl function
;*                     IOMW_SS, set scaling factors for current
;*                     session.
;*
;*                  The parmlist field in the request block points to
;*                  a 2 word structure.  The 1st word is the new row
;*                  scaling factor.  The 2nd word is the new column
;*                  scaling factor.  The input values must be > 0 and
;*                  <= Max_Scale.  A parameter error is set if any
;*                  value is out of range.
;*
;*  ENTRY POINT   :  IOMW_SS           LINKAGE:  CALL NEAR
;*
;*  INPUT         :  ES:BX points to the request block.
;*                   SI has offset to current session control block.
;*
;*  RETURN-NORMAL :  Session's scaling factors are updated.
;*
;*  RETURN-ERROR  :  Session's scaling factors are unchanged, the
;*                    Request Block status field set to error code.
;*
;*  EFFECTS       :  Stack is clean on return.  Regs not preserved.
;*
;*  INTERNAL REFERENCES:
;*           ROUTINES:  NONE.
;*
;*  EXTERNAL REFERENCES:
;*     ROUTINES:  NONE.
;*     DevHelps:  NONE.
;*
;**********************************************************************
;* PSEUDOCODE :
;*
;* BeginSub  IOMW_SS  (set session scaling factors)
;*
;* get new scale factors
;* IF <new scale factors are in range>
;*    disable system ints
;*    assign new scale factors to MSCB
;*    enable system ints
;* ELSE
;*    set parameter error
;* ENDIF
;* return
;*
;* EndSub  IOMW_SS
;*
;************************************************************************/

IOMW_SS  proc near

TempES     equ   <(word ptr [bp-2])>     ; local var for saving es
TempBX     equ   <(word ptr [bp-4])>     ; local var for saving bx

       Enter 4,0
       mov  TempES, es                   ; Save Request Block Address
       mov  TempBX, bx

       les  di, es:[bx].GIOParaPack      ; load selector to data area
       mov  dx, es:[di].Parm1            ; Get input Row Scale Factor
       mov  cx, es:[di].Parm2            ; Get input Col Scale Factor

       .if <dx gt 0>         AND         ; Check to make sure that the
       .if <dx le Max_Scale> AND         ; new scaling factors are both
       .if <cx gt 0>         AND         ; in the valid range.  If so
       .if <cx le Max_Scale>             ; then assign the new factors
          cli                            ; Hold interrupts for data update
          mov  [si].RowScale_Fact, dx    ; Assign new Scaling factors
          mov  [si].ColScale_Fact, cx
          xor  ax, ax                    ; Setup to Clear fields
          mov  [si].Row_Remain, ax       ; Clear row remainder field
          mov  [si].Col_Remain, ax       ; Clear col remainder field
          mov  [si].Row_Cell_Remain, ax  ; Clear row pixel remainder
          mov  [si].Col_Cell_Remain, ax  ; Clear col pixel remainder
          sti                            ; restore system ints
       .else                             ; If invalid Scaling Factor(s) then
          ParmErr                        ; Flag Invalid Parm Error
       .endif                            ; Input Scaling Factor Tests

       mov  es, TempES
       mov  bx, TempBX
       Leave

       ret                              ; Return to IOCTL Handler Rtn.

IOMW_SS  EndP



;**********************************************************************
;*
;*  FUNCTION NAME :  IOMW_EM    (54h)
;*
;*  DESCRIPTION   :  Performs the Mouse IOCtl function
;*                     IOMW_EM, set session's event mask.
;*
;*                   The parmlist field in the request block points to
;*                   the new 1 word event mask.  The event mask must
;*                   be in range.  Ints disabled while event mask is
;*                   updated.
;*
;*  ENTRY POINT   :  IOMW_EM           LINKAGE:  CALL NEAR
;*
;*  INPUT         :  ES:BX points to the request block.
;*                   SI has offset to current session control block.
;*
;*  RETURN-NORMAL :  Session's event mask is updated.
;*
;*  RETURN-ERROR  :  Session's event mask is unchanged, the
;*                   request block status field set to error code.
;*
;*  EFFECTS       :  Stack is clean on return.  AX, CX, DX, DI, and
;*                   SI registers contents are destroyed.
;*
;*  INTERNAL REFERENCES:
;*     ROUTINES:  NONE.
;*
;*  EXTERNAL REFERENCES:
;*     ROUTINES:  NONE.
;*     DevHelps:  NONE.
;*
;**********************************************************************
;* PSEUDOCODE :
;*
;* BeginSub  IOMW_EM  (set session event mask)
;*
;* calculate max event mask from number of mouse buttons
;* IF <new event mask is lt max event mask>
;*    disable system ints
;*    set new event mask in MSCB
;*    enable system ints
;* ELSE
;*    set parameter error
;* ENDIF
;* return
;*
;* EndSub  IOMW_EM
;*
;************************************************************************

IOMW_EM  PROC  near

       ?frame = 0                     ; Define Local Stack frame
       LocalVar TempES, WORD
       LocalVar TempBX, WORD

       EnterProc
       mov  TempES, es                ; Save Request Block address
       mov  TempBX, bx

       les  di, es:[bx].GIOParaPack   ; load selector to data area
       mov  ax, es:[di]               ; Get new event mask

       .if <ax le fs:EMaskMax>        ; If new event mask is valid then
          cli                         ; Hold interrupts for Data Updates
          mov  [si].E_Mask, ax        ; Save event mask in SG CB
          sti                         ; SG CB updated, allow interrupts
       .else                          ; If new event mask is invalid then
          ParmErr                     ; Set Parm Error Return code
       .endif                         ; Event Mask Tests

       mov  bx, TempBX                ; Restore Request Block address
       mov  es, TempES
       LeaveProc                      ; Clear Local Stack frame

       ret                            ; Return to Generic IOCtl Handler Rtn

IOMW_EM  ENDP


;**********************************************************************
;*
;*  FUNCTION NAME :  IOMW_TH  (55H)
;*
;*  DESCRIPTION   :  Performs the Mouse IOCtl function
;*                     IOMW_TH, set session threshold values.
;*
;*                   The parameter address field points to a 5 word
;*                   structure.  The 1st word is the length and should
;*                   be 10 for this IOCtl.  The 2nd word is the 1st
;*                   level movement rate.  The 3rd word is the 1st
;*                   level multiplier.  The 4th and 5th words are the
;*                   second level movement rate and multipliers re-
;*                   spectively.  All values are legal.
;*
;*  ENTRY POINT   :  IOMW_TH           LINKAGE:  CALL NEAR
;*
;*  INPUT         :  ES:BX points to the request block.
;*                   SI has offset to current session control block.
;*
;*  RETURN-NORMAL :  Session threshold vlaues updated.
;*
;*  RETURN-ERROR  :  Invalid Parameter error returned.
;*
;*  EFFECTS       :  Stack is clean on return. Regs not preserved.
;*
;*  INTERNAL REFERENCES:
;*     ROUTINES:  NONE
;*
;*  EXTERNAL REFERENCES:
;*     ROUTINES:  DDDD(Disable_Device, Enable_Device)
;*     DevHlps:   NONE.
;*
;**********************************************************************
;* PSEUDOCODE :
;*
;* BeginSub  IOMW_TH  (Set session threshold values)
;*
;*  call DDDD(Disable_Device) to disable the mouse
;*  IF <length of new threshold data OK>
;*     assign new threshold values and multipliers to session CB
;*  ELSE
;*     set PARAMETER ERROR
;*  ENDIF
;*
;*  call DDDD(Enable_Device) to enable the mouse
;*  return
;*
;* EndSub  IOMW_TH
;*
;************************************************************************

IOMW_TH  proc  near

       call DisableMouse       ; disable the mouse

       push es                 ; save es

       les  di, dword ptr es:[bx].GioParapacx    ; get address of ne values

       .if <es:[di].THLength eq 10>    and       ; if data length is ok and
       .if <es:[di].THLevel1 ne 0>     and       ; Level 1 is non 0 and
       .if <es:[di].THLevel2 ne 0>     and       ; Level 2 is non 0 and
       .if <es:[di].THLvl1Mplr ne 0>   and       ; 1st level mply is non 0 and
       .if <es:[di].THLvl2Mplr ne 0>   and       ; 1st level mply is non 0 and
       mov  cx, es:[di].THLevel1                 ; (get 1st level)
       mov  dx, es:[di].THLvl1Mplr               ; (get 1st multiplier)
       .if <<word ptr es:[di].THLevel2> ge cx> and  ; 2nd lvl >= 1st lvl and
       .if <<word ptr es:[di].THLvl2Mplr> ge dx>    ; 2nd mplr >= 1st Mplr

          mov  [si].Level1, cx                   ; put in MSCB
          mov  ax, es:[di].THLevel2              ; get 2nd level
          mov  [si].Level2, ax                   ; put in MSCB
          mov  [si].Lvl1Mplr, dx                 ; put in MSCB
          mov  ax, es:[di].THLvl2Mplr            ; get 2nd level multiplier
          mov  [si].Lvl2Mplr, ax                 ; put in MSCB
       .else
          pop  es                                ; restore es
          mov  es:[bx].PktStatus, INVALIDPARMS   ; Invalid Parm Error
          push es                                ; save es again
       .endif

       pop  es                                   ; restore es
       call EnableMouse                          ; enable the mouse

       ret

IOMW_TH  EndP


;**********************************************************************
;*
;*  FUNCTION NAME :  IOMW_PS    (56h)
;*
;*  DESCRIPTION   :  Performs the Mouse IOCtl function
;*                        IOMW_PS, set pointer image shape.
;*
;*                   Builds a pointer image definition record from
;*                   user input data.  Parmlist address points to the
;*                   new pointer image buffer.  Data address field
;*                   points to the new pointer definition record.
;*                   The new record is passed to the Pointer Draw DD.
;*                   If the new pointer is valid then Pointer Draw
;*                   will update the session control block with the
;*                   new pointer image data.
;*
;*  ENTRY POINT   :  IOMW_PS           LINKAGE:  CALL NEAR
;*
;*  INPUT         :  ES:BX points to the request block.
;*                   SI has offset to current session control block.
;*
;*  RETURN-NORMAL :  Session's pointer image is changed.  Foreground
;*                    pointer image on the display will change.
;*
;*  RETURN-ERROR  :  Session's pointer image data is unchanged,
;*                   Request Block Status field set to error code.
;*
;*  EFFECTS       :  Stack is clean on return.  Regs not preserved.
;*
;*  INTERNAL REFERENCES:
;*     ROUTINES:  None.
;*
;*  EXTERNAL REFERENCES:
;*     ROUTINES:  Ptr Draw(RemovePointer, DrawPointer,
;*                GetPointerMem, FreePointerMem) DDDD(Enable_-
;*                Device, Disable_Device)
;*
;*
;**********************************************************************
;* PSEUDOCODE :
;*
;* BeginSub  IOMW_PS  (set session pointer shape)
;*
;* call DDDD(Disable_Device) to disable the mouse
;* IF <current display mode is supported>
;*    IF <caller is foreground          AND
;*        ptr draw routines used        AND
;*        ptr overide flag is off       AND
;*        there is no ptr collision>
;*       call Ptr Draw(RemovePointer) to do unconditional remove
;*       set flag for redraw required
;*    ENDIF
;*    call Ptr Draw(FreePointerMem) to release current pointer image
;*    set up ptr definition record from user input image and definition
;*       data areas
;*    call Ptr Draw(GetPointerMem) to allocate new pointer image
;*    IF <new pointer image allocated OK>
;*       IF <redraw required>
;*          call Ptr Draw(DrawPointer) to draw new ptr image
;*       ENDIF
;*    ELSE
;*       set parameter error
;*    ENDIF
;* ELSE
;*    set parameter error
;* ENDIF
;* call DDDD(Enable_Device) to enable the mouse
;* return
;*
;* EndSub  IOMW_PS
;*
;************************************************************************

IOMW_PS  PROC  near

TempES        equ  <(word ptr [bp-2])>     ; For ES register
TempBX        equ  <(word ptr [bp-4])>     ; For BX register

       Enter 4,0
       mov  TempES, es                ; Save Request Block
       mov  TempBX, bx                ; Address

       call DisableMouse              ; Hold Mouse Interrupts for update

       test [si].D_Status, USS_Mode   ; See if display mode is supported.
       .if <z>  NEAR                  ; If so then OK to continue

          mov  bl, fs:FgndSessn       ; Get forground screen group #
          call PtrDrawCheck
          .if <ax eq 0>               ; If Not a Ptr Collision
             mov  al, fs:CallSessn    ; Get forground screen group #
             push cx                  ; Save current reg value
             mov  cx, 0               ; Flag Remove Ptr Required
             call RemovePointer       ; Hide Mouse Pointer Image
             pop  cx                  ; Restore previous reg value
          .endif                      ; Collision Area Test

          mov  al, fs:CallSessn          ; Get forground screen group #
          FreePointerMem                 ; Call Ptr Draw DD to free buffers

          lea  di, fs:Ptr_Rec            ; Setup DI to point to Ptr_Rec in DS
                                         ; Load Ptr Rec for Ptr Draw DD call
          mov  bx, TempBX                ; Restore Request Block Offset
                                         ; Ptr Rec Addr1 = Pointer Image Buf
          mov  ax, es:[bx.GIOParaPacx]       ; Get caller's Parmlist Parm addr
          mov  word ptr fs:[di].Addr1, ax    ; High word, & put in Ptr Rec
          mov  ax, es:[bx.GIOParaPacx+2]     ; Get caller's ParmList Parm addr
          mov  word ptr fs:[di].Addr1[2], ax ; Low word, & put in Ptr Rec

                                             ; Ptr Rec Addr2 = Ptr Def Record
          mov  ax, es:[bx.GIODataPacx]       ; Get caller's Data Parm address
          mov  word ptr fs:[di].Addr2, ax    ; High word, & put in Ptr Rec
          mov  ax, es:[bx.GIODataPacx+2]     ; Get caller's Data Parm address
          mov  word ptr fs:[di].Addr2[2], ax ; Low word, & put in Ptr Rec

          push fs
          pop  es                        ; Set ES:DI to point to Ptr_Rec
          mov  al, fs:CallSessn          ; Get foreground screen group #
          GetPointerMem                  ; Call Ptr Draw DD to get memory

          .if <ax eq 0>                  ; If GetPointerMem worked then
             mov  bl, fs:FgndSessn       ; Get forground screen group #
             call PtrDrawCheck           ; see ptr drawing OK
             .if <ax eq 0>               ; If Not a Ptr Collision
                mov  al, fs:CallSessn    ; Get forground screen group #
                call DrawPointer         ; Ensure Mouse Ptr is visible
             .endif                      ; New Ptr Collision Test
          .else                          ; If GetPointerMem failed then
            ParmErr                      ; Set ParmErr in Status field
          .endif                         ; GetPointerMem test
       .else
          ParmErr
       .endif

       call EnableMouse               ; Update done, Allow mouse interrupts
       mov  es, TempES                ; Restore Local Var's
       mov  bx, TempBX                ; Original Contents
       Leave                          ; Clear local Stack variables

       ret                            ; Return to IOCTL Handler Rtn

IOMW_PS  ENDP


;**********************************************************************
;*
;*  FUNCTION NAME :  IOMW_DP    (57h)
;*
;*  DESCRIPTION   :  Performs the Mouse IOCtl function
;*                     IOMW_DP, reset a session's collision area
;*                     and draw the pointer.
;*
;*                   Clears the session's collision area definition
;*                   fields.  If the caller is the FG session then the
;*                   pointer is drawn.  Ints are disabled during
;*                   access to the collision area definition fields.
;*
;*  NOTE          :  This function requires no input/output parameters.
;*
;*  ENTRY POINT   :  IOMW_DP           LINKAGE:  CALL NEAR
;*
;*  INPUT         :  ES:BX points to the request block.
;*                   SI has offset to current session control block.
;*
;*  RETURN-NORMAL :  Session's collision area is cleared. (always)
;*
;*  RETURN-ERROR  :  N/A
;*
;*  EFFECTS:  Stack is clean on return.  Regs not preserved.
;*
;*  INTERNAL REFERENCES:
;*     ROUTINES:  NONE.
;*
;*  EXTERNAL REFERENCES:
;*     ROUTINES:  Ptr Draw(DrawPointer), DDDD(Enable_Device,
;*                Disable_Device)
;*
;**********************************************************************
;* PSEUDOCODE :
;*
;* BeginSub  IOMW_DP  (remove session collision area and draw pointer)
;*
;* call DDDD(Disable_Device) to disable the mouse
;* set collision area flags to NO collision area defined
;* IF <ptr draw routines used AND
;*     display mode supported AND
;*     caller is foreground   AND
;*     ptr overide is OFF>
;*    call Ptr Draw(DrawPointer) to draw pointer image
;* ENDIF
;* call DDDD(Enable_Device) to enable the mouse
;* return
;*
;* EndSub  IOMW_DP
;*
;************************************************************************

IOMW_DP  proc  near

       push bx
       call DisableMouse              ; Hold Mouse Interrupts
       mov  [si].Area_Flags, 0000h    ; Clear collision area field flags
       mov  bl, fs:FgndSessn          ; Get forground screen group #
       call PtrDrawCheck
       .if <ax eq 0>                  ; if draws are OK
          mov  al, fs:CallSessn       ; Get forground screen group #
          call DrawPointer            ; Draw Mouse Pointer image
       .endif

       call EnableMouse               ; Update done, Allow mouse interrupts
       pop  bx
       ret                            ; Return to IOCTL Handler Rtn

IOMW_DP  ENDP


;**********************************************************************
;*
;*  FUNCTION NAME :  IOMW_RP    (58h)
;*
;*  DESCRIPTION   :  Performs the Mouse IOCtl function
;*                     IOMW_RP, define a collision area.
;*
;*                   The parmlist field in the request block points to
;*                   a 4 word structure which defines the collision
;*                   area.  1st two words is the upper left coordinates
;*                   2nd two words is the lower right coordinates.
;*                   If the two points are in reversed order then they
;*                   are swapped.  The defined collision are must be
;*                   in the display coordinate space.  The pointer
;*                   image will be removed if the caller is the FG and
;*                   the pointer is in the new collision area. It will
;*                   be redrawn if the pointer position is outside the
;*                   new collision area.
;*
;*  ENTRY POINT   :  IOMW_RP           LINKAGE:  CALL NEAR
;*
;*  INPUT         :  ES:BX points to the request block.
;*                   SI has offset to current session control block.
;*
;*  RETURN-NORMAL :  Session's collision area definition fields
;*                   are updated, and FG pointer image may be
;*                   removed or restored.
;*
;*  RETURN-ERROR  :  The screen group's collision area data remains
;*                   unchanged, an error return code is set in the
;*                   Request Block Status field.
;*
;*  EFFECTS       :  Stack is clean on return.  Regs not preserved.
;*
;*  INTERNAL REFERENCES:
;*     ROUTINES:  None.
;*
;*  EXTERNAL REFERENCES:
;*     ROUTINES:  Ptr Draw(RemovePointer, DrawPointer),
;*                DDDD(Disable_Device, Enable_Device)
;*     DevHelps:  VerifyAccess.
;*
;**********************************************************************
;* PSEUDOCODE :
;*
;* BeginSub  IOMW_RP   (define session collision area)
;*
;* IF <user defined values in reverse order>
;*    switch user defined coordinates
;* ENDIF
;*
;* IF <user defined coords are inside display mode type limits>
;*    call DDDD(Disable_Device) to disable the mouse
;*    IF <ptr draw routines are used AND
;*        display mode is supported  AND
;*        caller is foreground       AND
;*        ptr overide is OFF>
;*       set flag that drawing is OK
;*       IF <there is no ptr collision>
;*          call Ptr Draw(RemovePointer) to unconditionally remove ptr
;*       ENDIF
;*    ENDIF
;*    define collsion area with user defined collision area
;*    IF <drawing is OK AND
;*        there is no collision>
;*       call Ptr Draw(DrawPointer) to draw the pointer
;*    ENDIF
;*    call DDDD(Enable_Device) to enable the mouse
;* ELSE
;*    set parameter error
;* ENDIF
;*
;* return
;*
;* EndSub  IOMW_RP
;*
;***********************************************************************

IOMW_RP  PROC  near

TempES        equ  <(word ptr [bp-2])>     ; For ES register
TempBX        equ  <(word ptr [bp-4])>     ; For BX register

       Enter 4,0
       mov  TempES, es              ; Save Request Block Address
       mov  TempBX, bx

       les  di, es:[bx].GIOParaPack ; load selector to data area
       test [si].MType, Graphics
       .if nz                       ; If display in Graphics mode
          mov  cx, [si].GRow_Res    ; Get Graphics resolution values
          mov  dx, [si].GCol_Res    ; for parm checking
       .else                        ; If display in Text mode then
          mov  cx, [si].TRow_Res    ; Get Text resolution values
          mov  dx, [si].TCol_Res    ; for parm checking
       .endif                       ; Display mode test

       dec  cx                      ; Get Resolution Values as
       dec  dx                      ; Base: 0 thru (Res - 1)

       mov  ax, es:[di].R_Pos       ; Get Input Row Coords
       mov  bx, es:[di].R_End       ; For Collision Area

       .if <ax a bx>                ; If 1st Row coord larger
          mov  es:[di].R_Pos, bx    ; Than 2nd Row coord then
          mov  es:[di].R_End, ax    ; Reverse the defined order
       .endif                       ; Of the Row coordinates

       mov  ax, es:[di].C_Pos       ; Get Input Col Coords
       mov  bx, ES:[di].C_End       ; For Collision Area

       .if <ax a bx>                ; If 1st Col coord larger
          mov  es:[di].C_Pos, bx    ; Than 2nd Col coord then
          mov  es:[di].C_End, ax    ; Reverse the defined order
       .endif                       ; Of the Col coordinates

;*
;* Check the defined collision area for valid screen coordinates
;*

       .if <es:[di].R_Pos be cx> NEAR AND  ; Check starting row & col pos
       .if <es:[di].C_Pos be dx> NEAR AND
       .if <es:[di].R_End be cx> NEAR AND  ; Check Ending row & col pos
       .if <es:[di].C_End be dx> NEAR

          call DisableMouse          ; Hold Mouse Interrupts

          mov  bl, fs:FgndSessn      ; Get forground screen group #
          call PtrDrawCheck
          .if <ax eq 0>              ; If Not a Ptr Collision
             mov  al, fs:CallSessn   ; Get forground screen group #
             push cx                 ; Save current reg value
             mov  cx, 0              ; Flag Remove Ptr Required
             call RemovePointer      ; Hide Mouse Pointer Image
             pop  cx                 ; Restore previous reg value
          .endif                     ; Collision Area Test

          mov  [si].Area_Flags, 0001H  ; Update SG CB Collision Area
          mov  ax, es:[di].R_Pos       ; With caller's record values
          mov  [si].Area_Top, ax
          mov  ax, es:[di].C_Pos
          mov  [si].Area_Left, ax
          mov  ax, es:[di].R_End
          mov  [si].Area_Bot, ax
          mov  ax, es:[di].C_End
          mov  [si].Area_Right, ax

          mov  bl, fs:FgndSessn       ; Get forground session #

          call PtrDrawCheck           ; see it ptr draws OK
          .if <ax eq 0>               ; If Not a Ptr Collision
             mov  al, fs:CallSessn    ; Get forground screen group #
             call DrawPointer         ; Ensure Mouse Ptr is visible
          .endif                      ; New Ptr Collision Test

          call EnableMouse            ; Update done, Allow Mouse Intrpts

       .else                          ; If Collision Area Parms Invalid
          ParmErr                     ; Set Error Return in Status field
       .endif                         ; Collision Area Parm tests

       mov  bx, TempBX                ; Restore ES:BX to Request
       mov  es, TempES                ; Block Address

       sti                            ; Data updated, allow interupts
       Leave

       ret                            ; Return to IOCTL Handler Rtn

IOMW_RP  ENDP


;**********************************************************************
;*
;*  FUNCTION NAME :  IOMW_SP    (59h)
;*
;*  DESCRIPTION   :   Performs the Mouse IOCtl function
;*                     IOMW_SP, set pointer position.
;*
;*                   The parmlist field address field in the requset
;*                   block points to a 2 word structure.  The 1st word
;*                   is the new X coordinate, 2nd word is the new
;*                   column coordinate.  The new pointer position must
;*                   within the display coordinate space.  If the
;*                   caller is the foreground then the pointer is
;*                   hidden and redrawn.  Ints disabled while updating.
;*
;*  ENTRY POINT   :  IOMW_SP           LINKAGE:  CALL NEAR
;*
;*  INPUT         :  ES:BX points to the request block.
;*                   SI has offset to current session control block.
;*
;*  RETURN-NORMAL :  Session's pointer position is updated.
;*
;*  RETURN-ERROR  :  Session pointer position unchanged, request
;*                    block status field set to error code.
;*
;*  EFFECTS       :  Stack is clean on return.  Regs not preserved.
;*
;*  INTERNAL REFERENCES:
;*     ROUTINES:  None.
;*
;*  EXTERNAL REFERENCES:
;*     ROUTINES:  Ptr Draw(RemovePointer, DrawPointer), DDDD(
;*                Disable_Device, Enable_Device)
;*     DevHelps:  None
;*
;**********************************************************************
;* PSEUDOCODE :
;*
;* BeginSub  IOMW_SP  (set session pointer position)
;*
;* get new pointer pos
;* IF <new pointer pos is inside current display mode resolution>
;*    call DDDD(Disable_Device) to disable the mouse
;*    IF <ptr draw routines are used      AND
;*        current display mode supported  AND
;*        caller is foreground            AND
;*        session switch not in progress  AND
;*        there is no ptr collision>
;*       call Ptr Draw(RemovePointer) to unconditionally remove the ptr
;*    ENDIF
;*    set new pointer pos in MSCB
;*    IF <ptr draw routines are used      AND
;*        current display mode supported  AND
;*        caller is foreground            AND
;*        session switch not in progress  AND
;*        there is no ptr collision>
;*       call Ptr Draw(DrawPointer) to draw the ptr at the new position
;*    ENDIF
;*    call DDDD(Enable_Device) to enable the mouse
;* ELSE
;*    set parameter error
;* ENDIF
;* return
;*
;*EndSub  IOMW_SP
;*
;***********************************************************************


IOMW_SP  proc near

TempES   equ   <(word ptr [bp-2])>   ; temp storage for es
TempBX   equ   <(word ptr [bp-4])>   ; temp storage for bx

       Enter  4,0
       mov  TempES, es               ; Save Request Block Address
       mov  TempBX, bx

       les  di, es:[bx].GIOParaPack  ; load selector to data area
       mov  cx, es:[di].Parm1        ; Get new Row coordinate
       mov  dx, es:[di].Parm2        ; Get new Col coordinate

       test [si].Mtype, Graphics     ; Check current Display Mode
       .if z                         ; If in Text Mode then
          mov  ax, [si].TRow_Res     ; Get text mode row resolution
          mov  di, [si].TCol_Res     ; Get text mode col resolution
       .else                         ; If in Graphics Mode then
          mov  ax, [si].GRow_Res     ; Get graphics mode row resolution
          mov  di, [si].GCol_Res     ; Get graphics mode col resolution
       .endif                        ; Display Mode Tests

;*
;*    Now check the new position to make sure that it is in the current
;*    display mode limits.  If so then if the old pointer position is visible
;*    it is removed.  Then the new position is set and the image drawn if
;*    it should be visible.
;*

       .if <cx ge 0>  AND            ; Validate new Ptr Row coordinate
       .if <cx lt ax> AND            ;  X >= 0 AND X < current row res
       .if <dx ge 0>  AND            ; Validate new Ptr Col coordinate
       .if <dx lt di>                ;  Y >= 0 AND Y < current col res
          call  MOVEPTR              ; move pointer to new position @131957
       .else                         ; If input values are invalid then
          ParmErr                    ; Set Invalid Parm Error
       .endif                        ; Input Ptr Coord Tests

       mov  bx, TempBX               ; Restore ES:BX to Request
       mov  es, TempES               ; Block Address
       Leave

       ret                           ; Return to IOCTL Handler Rtn.
IOMW_SP  ENDP


;**********************************************************************
;*
;*  FUNCTION NAME :  IOMW_SD (5A)
;*
;*  DESCRIPTION   : Performs the mouse IOCtl function
;*                    IOMW_SD, register a Pointer Draw DD for a
;*                    protect mode session.
;*
;*                   The parmlist field of the request block points to
;*                   a 3 word structure.  The 1st two words is the FAR
;*                   address to the Pointer Draw entry point.  The 3rd
;*                   word is the Pointer Draw data selector.  The data
;*                   list field points to a 3 word structure.  1st is
;*                   the structure length (6), 2nd is display config #
;*                   the pointer is switching to, 3rd is who the call
;*                   is coming from (0 = app, 1 = BVS).  This IOCtl is
;*                   generated on every MOUOPEN call.  For BVS the ptr
;*                   is always removed and the set mode window flag is
;*                   set.  This is the beginning of a set mode
;*                   sequence if BVS is the caller.
;*
;*                   A word is allocated on the local stack frame that
;*                   is used as a local status word.  The bits are
;*                   defined as follows:  bits 15-4, reserved, bit 3 -
;*                   set if configuration number is changing, bit 2 -
;*                   set if ptr image was removed and may need to be
;*                   redrawn, bit 1 - set if ptr draw address is
;*                   changing, bit 0 - set if BVS is the caller.
;*
;*  ENTRY POINT   :  IOMW_SD           LINKAGE:  CALL NEAR
;*
;*  INPUT         :  ES:BX points to the request block.
;*                   SI has offset to current session control block.
;*
;*  RETURN-NORMAL :  Session's Pointer Draw entry point changed.
;*
;*  RETURN-ERROR  :  N/A
;*
;*  EFFECTS       :  Stack is clean on return.  Regs not preserved.
;*
;*  INTERNAL REFERENCES:
;*     ROUTINES:  CheckAccess, GetCfgDataOffset, GetExtModeData.
;*
;*  EXTERNAL REFERENCES:
;*     ROUTINES:  Ptr Draw(DrawPointer, RemovePointer, Check-
;*                ModeProtect), DDDD(Enable_Device, Disable_-
;*                Device)
;*     Dev Helps: None
;*
;**********************************************************************
;* PSEUDOCODE :
;*
;* BeginSub  IOMW_SD  (register ptr draw routine for a session)
;*
;* check access to data area (caller information from BVS)
;* IF <data list pointer is not NULL>
;*    IF <length of data area is 6>
;*       IF <caller value is 1>
;*          set status to BVS is the caller
;*          set setmode window flag
;*       ENDIF
;*       get config # from data area
;*       IF <config # is new/different from current>
;*          set status to config # is changing
;*          save new config #
;*       ENDIF
;*    ENDIF
;* ENDIF
;*
;* get new ptr draw entry point
;* IF <new entry pt is different from current>
;*    set status to show ptr draw is changing
;* ENDIF
;* IF <(BVS is caller OR ptr draw changing OR config # changing) AND
;*     Ptr draw routines are used for drawing                    AND
;*     display mode is supported                                 AND
;*     caller is foreground                                      AND
;*     ptr overide flag is off                                   AND
;*     there is no collision>
;*    call Ptr Draw(RemovePointer) to unconditionally remove the ptr
;*    set status to show redraw may be needed
;* ENDIF
;*
;* IF <ptr draw changing OR config # changing>
;*    assign new ptr draw entry point
;*    IF <BVS is NOT the caller>
;*       IF <display mode is currently available>
;*          IF <config # is changing>
;*             call GetCfgDataOffset to get new cfg data offset
;*             IF <offset returned>
;*                store sel:off in MSCB for ptr draw use
;*             ELSE
;*                0 out sel:off to show no config data available
;*             ENDIF
;*          ENDIF
;*          build a display mode record
;*          call Ptr Draw(CheckModeProt) to check curren mode
;*          IF <current display mode is supported>
;*             set device status to supported mode
;*             IF <pointer image needs to be redrawn>
;*                call Ptr Draw(DrawPointer) to draw the ptr
;*             ENDIF
;*          ELSE
;*             set device status to unsupported mode
;*          ENDIF
;*       ENDIF
;*    ENDIF
;* ENDIF
;*
;* return
;*
;* EndSub  IOMW_SD
;*
;***********************************************************************

IOMW_SD  PROC  near

       ?frame = 0                         ; Get Local/Temp Stack Frame
       LocalVar TempES, WORD              ; For ES register
       LocalVar TempBX, WORD              ; For BX register
       LocalVar TempSI, WORD              ; For SI register
       LocalVar TempDS, WORD              ; for ds register
       LocalVar Status, WORD              ; for local status
       LocalVar NewCfg, WORD              ; for new config number
;*
;* These equates are used to set bits in the Status word.
;*

BVSCall     EQU     0001h
PtrChange   EQU     0002h
PtrRedraw   EQU     0004h
CfgChange   EQU     0008h


       EnterProc
       mov  TempES, es                    ; Save Request Block Address
       mov  TempBX, bx
       mov  TempSI, si                    ; Save Input SG CB Offset
       mov  TempDS, ds                    ; save ds
       mov  Status, 0                     ; set status to 0

       call DisableMouse                  ; disable the mouse

;*
;* Check access to data area.  First check and see that we can load the
;* passed selector offset.  This is for compatibilty because we never checked
;* to make sure that the pointer was a dword of 0's in the past.  If that
;* access fails then we assume that an old subsystem is calling and will
;* not set the BVS calling status bit.  If the access is OK then we will
;* check access to the data area.  If access then fails to the data area,
;* we will fail with a parameter error.
;*

       test word ptr es:[bx].GIODataPack+2, 0fff8h
       .if <nz>
          les  di, es:[bx].GIODataPack
          .if <es:[di].DLLen eq 6>          ; if valid length field
             .if <es:[di].DLCaller eq 1>    ; if BVS is the caller
                or  Status, BVSCall         ; then set BVS caller bit
             .endif                         ;
             mov  bx, es:[di].DLCfg         ; get new config number
             .if <bx ne [si].Cur_Config>    ; if new config is different
                or   Status, CfgChange      ; show that cfg has changed
                mov  NewCfg, bx             ; save new config #
             .endif                         ; end config changed test
          .endif                            ; ignore invalid length
       .endif                               ;

;*
;* Now set flag indicating that ptr draw is changing or not and set the
;* set mode window active if BVS is the caller.  Also remove the pointer if
;* needed. Removal is done by current pointer draw, not new one.
;*

       mov  es, TempES                       ; restore request packet sel
       mov  bx, TempBX                       ; restore offset
       les  di, es:[bx].GIOParaPack          ; get address to ptr draw data
       mov  ax, word ptr es:[di].Addr1+2     ; get current ptr entry
       mov  dx, word ptr es:[di].Addr1       ; point
       mov  cx, word ptr es:[di].Addr2       ; data selector
       push ax
       push dx
       push cx
       .if <ax ne <word ptr [si].Screen_Entp+2>> OR  ; if ptr entry pt
       .if <dx ne <word ptr [si].Screen_Entp>>   OR  ; has changed, or
       .if <cx ne <word ptr [si].Screen_DSeg>>       ; data sel changed
          or  Status, PtrChange              ; then set change status
       .endif                                ;

       mov  bl, fs:FgndSessn                ; get foreground session
       test Status, BVSCall+PtrChange+CfgChange  ; BVS caller or ptr draw
       .if nz     ; add and to change back ; has changed or cfg change
          call PtrDrawCheck
          .if <ax eq 0>                   ; If Not a Ptr Collision
             mov  al, fs:CallSessn          ; set foregrnd session
             push cx                        ; save cx
             xor  cx, cx                    ; unconditional remove
             call RemovePointer             ; Hide Mouse Pointer Image
             pop  cx                        ; restore cx
             or  Status, PtrRedraw          ; ptr needs to be redrawn
          .endif                            ; Collision Area Test
       .endif
       pop  cx
       pop  dx
       pop  ax

;*
;* Now register the new pointer draw if either the ptr draw DD or the
;* display configuration number changed.  If BVS is not the caller then
;* verify the current mode data with the new pointer draw.
;*

       test Status, PtrChange+CfgChange       ; if ptr draw or cfg change
       .if nz  NEAR                           ; then register new one
          mov  word ptr [si].Screen_Entp, dx  ; save in session CB
          mov  word ptr [si].Screen_Entp+2, ax ; save in session CB
          mov  word ptr [si].Screen_DOff, 0   ; zero offset
          mov  word ptr [si].Screen_DSeg, cx  ; save in session CB

;*
;*         Now see if the configuration has changed.  If so then store the
;*         new configuration data information in the session control block.
;*         If BVS is the caller then a subsequent set mode will be done and
;*         this new configuration data will be checked.  If BVS is not the
;*         caller then a check of the current mode is forced.  If no mode
;*         data is available then leave the mouse in its current state.
;*

          test Status, CfgChange          ; see if cfg changed
          .if <nz>                        ; if it has then
             mov  bx, NewCfg              ; get new config num
             call GetCfgDataOffset        ; go get the offset
             .if <nc>                     ; if offset found then
                mov  [si].Cur_Config, bx  ; save new config number
                mov  [si].CfgOffset, dx   ; put data offset in CB
                mov  [si].CfgSelector, fs ; put selector in CB
             .else                        ; offset not found
                mov  [si].CfgOffset, 0    ; zero out the config data
                mov  [si].CfgSelector, 0  ; pointer in the CB
             .endif
          .endif

;*
;*         Now see if BVS is the caller.  If not then build a mode data
;*         structure and call PtrDraw to check it.


          test Status, BVSCall                ; see if BVS is the caller
          .if z  NEAR                         ; if not then verify mode
             .if <[si].MLength ne 0> NEAR       ; if mode data available
                push fs
                pop  es                      ; es pts to our data seg
                mov  di, offset Modes        ; get offset of mode struc
                push di                      ; save offset of mode struc
                mov  cx, BaseModeLen         ; get Base Mode data length
                add  si, Mlength             ; offset to mode data in CB
                cld                          ; go forwart
                rep  movsb                   ; move base mode data
                mov  cx, ExtModeLen          ; max len of extended data
                mov  al, fs:CallSessn        ; calling session
                xor  ah, ah                  ; convert to word value
                call GetExtModeData          ; get the extended mode data
                pop  di                      ; restore offset mode struc
                mov  si, TempSI              ; restore CB offset
                mov  ds, TempDS              ; restore our data selector

                CheckModeProtect             ; verify data with new ptr draw

                .if <ax eq 0>                ; If Mode is supportable then
                   and  [si].D_Status, NOT USS_Mode  ; show supported mode
                   mov  bl, fs:FgndSessn
                   test [si].D_Status, PtrDraw ; If Ptr Draw Rtns Used
                   call PtrDrawCheck
                   .if <ax eq 0>          ; If Not a Ptr Collision
                      mov  al, fs:CallSessn ; Get caller's screen group #
                      call DrawPointer      ; Ensure Mouse Ptr is visible
                   .endif                   ; New Ptr Collision Test

                .else                          ; Mode is unsupported so
                   or   [si].D_Status, USS_Mode  ; set unsupported mode
                .endif                         ; supported mode tests
             .endif
          .endif                            ; BVS is caller test
       .endif                               ; ptr draw or cfg change test

sd1:
       mov  es, TempES                      ; restore registers
       mov  bx, TempBX
       mov  si, TempSI                      ; Save Input SG CB Offset
       mov  ds, TempDS                      ; save ds

       test Status, BVSCall                 ; see if BVS is the caller
       .if nz                               ; if so then this is the
          or  [si].Ptr_Flags, SM_WinFlag    ; start of set mode sequence
       .endif                               ;

       call EnableMouse

       LeaveProc                          ; Clear local Stack variables

       RET                                ; Return to IOCTL Handler Rtn
IOMW_SD  ENDP


;**********************************************************************
;*
;*  FUNCTION NAME :  IOMW_DS  (5C)
;*
;*  DESCRIPTION   :  Performs the Mouse IOCtl function
;*                     IOMW_DS, set device status flags.
;*
;*                  The parmlist field in the request block points to
;*                  a new 1-word device status flag.  See Tech Ref
;*                  for definition of each flag.  If singleQ mode is
;*                  activated then mouse "attaches" itself to the
;*                  singleQ device driver.  Reserved bits may not be
;*                  set.  Any further request to start singleQ mode
;*                  by the same caller is ignored.
;*
;*  ENTRY POINT   :  IOMW_DS           LINKAGE:  CALL NEAR
;*
;*  INPUT         :  ES:BX points to the request block.
;*                   DS:SI has offset to current session control block.
;*
;*  RETURN-NORMAL :  Session's device status flags are updated.
;*
;*  RETURN-ERROR  :  Session's device status flags are unchanged,
;*                   status field in request block set to error code.
;*
;*  EFFECTS       :  Stack is clean on return.  Regs not preserved.
;*
;*  INTERNAL REFERENCES:
;*     ROUTINES:  GetExtModeData, FlushMonChain
;*
;*  EXTERNAL REFERENCES:
;*     ROUTINES:  Ptr Draw(RemovePointer, CheckModeProtect),
;*                DDDD(Enable_Device, Disable_Device), SQ DD
;*     DevHlps:   AttachDD, ProcRun
;*
;**********************************************************************
;* PSEUDOCODE :
;*
;* BeginSub  IOMW_DS  (set session device status)
;*
;* call DDDD (Disable_Device) to disable the mouse
;* IF <new device status mask is valid>
;*    IF <new device status mask is different>
;*
;*
;*** Enable/Disable ptr draw routines.
;*
;*
;*       IF <ptr draw routines are currently used>
;*          IF <ptr draw routines are being disabled AND
;*              display mode is supported            AND
;*              caller is foreground                 AND
;*              pointer overide is OFF               AND
;*              there is no collision>
;*             call Ptr Draw(RemovePointer) unconditional remove
;*          ENDIF
;*       ELSEIF <ptr draw routines are being enabled>
;*          build a display mode data record
;*          set ptr draw routines used in device status
;*          call Ptr Draw(CheckModeProt) to check mode
;*          IF <display mode is supported>
;*             set device status to supported mode
;*          ELSE
;*             set device status to unsupported mode
;*          ENDIF
;*          set ptr draw routines not used in device status
;*       ENDIF
;*
;*
;*** data report format.
;*
;*
;*       IF <data report format is changing>
;*          call FlushMonChain to flush monitors and event queue
;*          IF <flush failed>
;*             set flag for fail set device status
;*          ENDIF
;*       ENDIF
;*
;*
;*** SingleQ mode enable/disable
;*
;*
;*       IF <activate SQ mode request>
;*          IF <no process has activated SQ mode>
;*             IF <SQ mode is not active>
;*                call Device_Help(AttachDD) to attach to SQDD
;*                IF <attach worked>
;*                   call SQDD(initialize) for mouse data
;*                   IF <initialize call worked>
;*                      set SQ ownership PID to current PID
;*                      IF <Queue flush not in progress>
;*                         call FlushMonChain to flush data
;*                      ELSE
;*                         set flag indicating queue flush done
;*                      ENDIF
;*                      IF <queue flush was done>
;*                         IF <thread blocked on mouse data>
;*                            call Device_Help(ProcRun) to wake up
;*                         ENDIF
;*                      ENDIF
;*                   ELSE
;*                      set flag to fail set device status
;*                   ENDIF
;*                ELSE  /* attach failed */
;*                   set flag to fail set device status
;*                ENDIF
;*             ENDIF
;*          ELSE  /* SQ has a process owner  */
;*             IF <calling PID is not same as SQ owner PID>
;*                set flag for invalid parameters
;*             ENDIF
;*          ENDIF
;*       ELSE    /* could be a reset SQ mode request  */
;*          IF <SQ mode is active    AND
;*              caller ownes SQ mode>
;*             call SQDD(endinput) to end mouse input
;*          ENDIF
;*       ENDIF
;*
;*
;*** set cmpletion status
;*
;*
;*       IF <failure indicated>
;*          set general failure
;*       ELSEIF <parameter error indicated>
;*          set parameter error
;*       ELSE
;*          set new device status
;*       ENDIF
;*
;*    ENDIF  /* new status same as old  */
;* ELSE      /* new status is invalide  */
;*    set parameter error
;* ENDIF
;*
;* call DDDD(Enable_Device) to enable the mouse
;* return
;*
;* EndSub  IOMW_DS
;*
;***********************************************************************/

IOMW_DS  proc near

TempES      equ   <(word ptr[bp-2])>   ; temp storage
TempBX      equ   <(word ptr[bp-4])>
SetStatus   equ   <(word ptr[bp-6])>

    Enter  6,0
    mov  TempES, es                    ; Save Request Block address
    mov  TempBX, bx
    mov  SetStatus, 0                  ; Clear Internal Error Flag

    les  di, es:[bx].GIOParaPack       ; load selector to data area
    call DisableMouse                  ; Hold Mouse Interrupts

    mov  cx, [si].D_Status             ; Get SG device status field flags
    mov  ax, word ptr es:[di]          ; Get new SG dev status user flags

;*
;*   First make sure that the new status is valid.  If so then see if it is
;*   changing.  If so then continue
;*

    test ax, NOT DevStatSetMax         ; see if any non settable bits set
    .if <z>              NEAR          ; If not and the new mask
       .if <ah ne ch>    NEAR          ; is different

;*
;*   If pointer draw calls for drawing operations are currently acitve
;*   and the new device status is disabling them then remove the current
;*   pointer image.
;*

          test [si].D_Status, PtrDraw  ; Check Ptr Draw Usage Flag
          .if <z>                      ; If Ptr Draw is Active then
             mov  bl, fs:FgndSessn     ; Get FG SG ID #
             test ax, PtrDraw          ; Check New Ptr Draw Flag Bit
             .if <nz>                  ; If we are disabling it
                call PtrDrawCheck      ; go see if we can call ptr draw
                .if <ax eq 0>          ; If so then
                   mov  al, fs:CallSessn ; Get forground screen group #
                   push cx             ; Save current reg value
                   xor  cx, cx         ; Flag Remove Ptr Required
                   call RemovePointer  ; Hide Mouse Pointer Image
                   pop  cx             ; Restore previous reg value
                .endif                 ; Collision Area Test
             .endif                    ; Ptr Image Visibility Tests

;*
;*     If pointer draw calls are disabled and the new device status is
;*     enabling them then we must check the current mode data to make
;*     sure that we can draw.  The reason is that a mode may be only
;*     partially supported when ptr draw calls are disabled, but un-
;*     supported when they are enabled.
;*

          .else                      ; else ptr draw is currently not active

             test ax, PtrDraw        ; Is ptr draw being enabled ?
             .if  z                  ; Yes, is so check the display mode
                push di
                push es
                push fs              ; save our data sel
                push fs              ; setup es:di as destination
                pop  es
                mov  di, offset Modes
                push di
                push si
                add  si, MLength         ; set ds:si as src of base mode data
                mov  cx, BaseModeLen     ; base mode data lenght in bytes
                cld                      ; go forward
                rep  movsb               ; move base mode data
                mov  cx, ExtModeLen      ; length of extended mode data
                mov  al, fs:CallSessn    ; calling session
                xor  ah, ah              ; make word
                call GetExtModeData      ; get the extended mode data
                pop  si                  ; restore saved registers
                pop  di
                CheckModeProtect         ; go check the mode data
                pop  fs
                pop  es
                pop  di
                .if <ax eq 0>            ; was mode supported
                   and  [si].D_Status, NOT USS_Mode  ; display mode valid
                .else                           ; mode is unsupported
                   or  [si].D_Status, USS_Mode  ; set unsupported mode
                .endif                          ; end mode supported test
             .endif                             ; end ptr draw enabled test
          .endif                                ; Ptr Draw Rtn Override Test

;*
;*         Now see if the reporting format is changing.  This would be from
;*         mickey data to screen position or the other way.  If the format
;*         is changing then flush the monitor chain to get rid of any old
;*         formatted data.
;*

          mov  ax, word ptr es:[di]    ; Get new SG dev status user flags
          mov  cx, [si].D_Status       ; Get SG device status field flags

          and  ax, MickeyData          ; Check Data Format Flag Bits
          and  cx, MickeyData          ; For both Current & New Masks

          .if <ah ne ch>               ; If Data formats are different

             call FlushMonChain        ; Flush the monitor chain and evnt que

             .if c                     ; If MonFlush failed then
                mov  SetStatus, 1      ; Flag General Failure
             .endif                    ; MonFlush Completion Tests
          .endif                       ; Data Format Change Test

;*
;*         Now determine is single queue mode is being enabled or disabled.
;*

          mov  ax, word ptr es:[di]              ; Get new dev status flags

;*
;*         If SQ mode is being activated then attach to the singleq device
;*         driver and initialize the IDC interface.  If this works then the
;*         monitor chain is flushed.  If a process is blocked on data then
;*         it is unblocked, which will cause an error to be returned on the
;*         read request (part of another thread) since SQ mode will be active.
;*

          test ax, SQ_Mode                       ; Get SQ Input Mode Flag Mask
          .if  nz  NEAR                          ; If SQ Activate Request then
             .if <fs:SQ_Pid eq 0> NEAR           ; no active SQ yet

                test [si].D_Status, SQ_Mode      ; Check SQ Mode Flag Bit
                .if  z  NEAR                     ; If SQ Input Mode InActive

                   push di                       ; Save New Mask Offset

                   lea  bx, fs:SQDDName          ; Offset for SQ DD Name
                   lea  di, fs:SQDD              ; Offset to Data Record
                   mov  dl, DevHlp_AttachDD      ; DevHelp Function Number
                   call fs:Device_Help           ; Invoke AttachDD Function

                   pop  di                       ; Restore New Mask Offset

                   .if nc  NEAR                  ; If Attach DD worked then

                     mov   ax, fs:Eq_Length      ; Get Event Queue Byte Size
                     mov   cx, ElRec_Size        ; Get Que Element Rec Size
                     div   cl                    ; Calculate # of Elements
                     cbw                         ; Get Element Count as Word
                     mov   cx, Que_Header_Size   ; Get Element Header Size
                     mul   cl                    ; Calc # Header Bytes
                     add   ax, fs:Eq_Length      ; Add required Byte Count

                     mov   cx, ax                ; Total Byte Cnt
                     mov   bx, 0001H             ; SQ DD Init & FIFO Buf
                     mov   ax, 0200H             ; Mouse DD calling
                     push  es                    ; Save User Data Selector
                     push  fs:SQDD.ProtDS        ; Get SQ DD DS Selector
                     pop   es                    ; Load into ES for call
                     call  dword ptr fs:SQDD.ProtEntry ; Invoke SQ DD Init Func
                     pop   es                    ; Restore User Data Selector

                      .if <ax eq 0> NEAR         ; If SQ Init worked then

                         mov  cx, fs:CallPID           ; get callers PID
                         mov  fs:SQ_Pid, cx            ; Save in SQ PID

                         test [si].D_Status, Q_Flush   ; Check Flush Bit
                         .if  z                        ; AOK to Flush Que
                            call FlushMonChain         ; go flush mon chain
                         .else                         ; If Flush in Progress
                            clc                        ; Set DevHlp worked Flag
                         .endif                        ; Event Que Flush Tests

                         .if  nc                       ; If MonFlush worked

                            test [si].D_Status, Block_Mask ; Check Block Bit
                            .if  nz                    ; If Thread(s) Blocked
                               mov  bx, ds             ; SG que addr low word
                               mov  ax, [si].E_Queue   ; SG que addr high word
                               mov  dl, DevHlp_ProcRun ; Specify DevHlp Func
                               call fs:Device_Help     ; Invoke Run Function
                            .endif                     ; Blocked Thread test

                         .else                      ; If MonFlush failed then
                            mov  SetStatus,  1      ; Flag General Failure
                         .endif                     ; MonFlush Completion Tests

                      .else                   ; If SQ Init failed then
                        mov  SetStatus, 1     ; Flag General Failure
                      .endif                  ; SQ DD Init Function Tests

                   .else                      ; If Attach DD failed then
                      mov  SetStatus, 1       ; Flag General Failure
                   .endif                     ; Attach DD Tests
                .endif                        ; SQ Mode InActive Test

             .else                            ; SQ already active then
                mov  ax, fs:SQ_Pid            ; Get PID of SQ owner
                .if <ax ne fs:CallPID>        ; If Caller not owner then error
                   mov  SetStatus, 2          ; Flag Invalid parameter
                .endif                        ; Caller not owner test
             .endif                           ; Shell SQ ID Tests

          .else                               ; If not a Set SQ Mode request

             mov  ax, fs:SQ_Pid               ; Get single queue PID
             .if <fs:CallPID eq ax> AND       ; See if caller owns SQ
             test [si].D_Status, SQ_Mode      ; Check SQ Mode Flag Bit &
             .if  nz                          ; If SQ Input Mode Active

                mov  ax, 0200H                ; Specify Mouse DD calling
                mov  bx, 0003H                ; Specify SQ DD End Function
                push es                       ; Save User Data Selector
                push fs:SQDD.ProtDS           ; Get SQ DD DS Selector
                pop  es                       ; Load into ES for call
                call dword ptr fs:SQDD.ProtEntry ; Invoke SQ DD End Func
                pop  es                       ; Restore User Data Selector
                mov  word ptr fs:SQ_Pid, 00H  ; Reset SQ Pid as available

             .endif                           ; End SQ Input Mode Tests
          .endif                              ; SQ Input Mode Activate Tests

;*
;*         If every thing was OK then set the new device status
;*

          .if <SetStatus eq 0>         ; If Mask Bits are verified then
             mov  ax, word ptr es:[di] ; Get new SG dev status user flags
             mov  cx, [si].D_Status    ; Get SG device status field flags
             mov  al, cl               ; Keep current Status Flags low byte
             mov  [si].D_Status, ax    ; Set new SG Status Flags high byte
          .elseif <SetStatus eq 1>     ; If General code failure then
             GenFail                   ; Flag General Failure in code
          .elseif <SetStatus eq 2>     ; If Invalid Parm error then
             ParmErr                   ; Flag Invalid Mask Parameter
          .endif                       ; Mask Processing Verifications

       .endif

    .else                              ; Non settable bits where set
       ParmErr                         ; Flag user parameter error
    .endif                             ; New Mask Tests

    call EnableMouse                   ; Allow Mouse Interrupts

    mov  es, TempES                    ; Restore Request Block address
    mov  bx, TempBX

    Leave                              ; Clear Local stack frame

    ret                                ; Return to Generic IOCtl Handler Rtn
IOMW_DS  ENDP

;**********************************************************************
;
;  FUNCTION NAME :  IOMW_MD    (5Dh)
;
;  DESCRIPTION   :  Performs the Mouse IOCtl function
;                     IOMW_MD, display mode change is complete.
;
;                   This IOCtl is used to tell the mouse that the
;                   mode switch has completed and is now active.  If
;                   the caller is FG then the pointer is redrawn if
;                   the new mode is supported.  This IOCtl works in
;                   conjunction with IOCtl IOMW_SM (51h).
;
;  ENTRY POINT    : IOMW_MD         LINKAGE: CALL NEAR
;
;  INPUT          :  ES:BX points to the request block.
;                    SI has offset to current session control block.
;
;  RETURN-NORMAL  :  Always,  pointer is redrawn if necessary.
;
;  RETURN-ERROR   :  N/A
;
;  EFFECTS        :  Stack is clean on return.  AX, CX, & DI registers
;                    are changed.
;
;  INTERNAL REFERENCES:
;     ROUTINES:  None.
;
;  EXTERNAL REFERENCES:
;     ROUTINES:  Ptr Draw(DrawPointer)
;                DDDD(Enable_Device, Disable_Device)
;     DevHelps:  NONE.
;
;**********************************************************************
;* PSEUDOCODE :
;*
;* BeginSub  IOMW_MD   (end of display mode switch)
;*
;* call DDDD(Disable_Device) to disable the mouse
;* clear setmode window flag
;* call Ptr Draw(DrawPointer) to draw ptr if needed
;* call DDDD(Enable_Device) to enable the mouse
;* return
;*
;* EndSub  IOMW_MD
;*
;***********************************************************************


IOMW_MD  PROC  near


       push bx                               ; save bx
       call DisableMouse                     ; disable the mouse

       and  [si].Ptr_Flags, NOT SM_WinFlag   ; Reset sem mode window flag
       push si                                                            ;emi

       mov  bl, fs:FgndSessn                 ; get FG session
       call PtrDrawCheck
       .if <ax eq 0>                         ; If Not a Ptr Collision
          mov  al, fs:CallSessn              ; forground screen group #
          call DrawPointer                   ; go draw the pointer image
       .endif                                ; Collision Area Test
       pop  si                                                            ;emi

       add  si, MLength                                                   ;emi
       xor  ch, ch                                                        ;emi
       mov  cl, fs:CallSessn                                              ;emi
       xor  bh, bh                                                        ;emi
       mov  bl, fs:FgndSessn                                              ;emi
       push es                                                            ;emi
       call Emi_EndVMChange                  ; cx = caller's session      ;emi
                                             ; bx = future   session      ;emi
                                             ; ds:si = video data         ;emi
       pop  es                                                            ;emi

       call EnableMouse                      ; enable the mouse
       pop  bx                               ; restore bx

       ret                                   ; return to IOCtl routine

IOMW_MD ENDP

; GRADD START

;      /******************* START OF SPECIFICATIONS *********************/
;      /*                                                               */
;      /*  SUBROUTINE NAME:  IOMW_RG    (5eh)                           */
;      /*                                                               */
;      /*  DESCRIPTIVE NAME:  Performs the Mouse IOCtl function         */
;      /*                     IOMR_RG, to register/deregister the       */
;      /*                     task time only pointer draw.              */
;      /*                                                               */
;      /*  INPUT:  ES:BX points to the request block.                   */
;      /*          SI has offset to current session control block.      */
;      /*                                                               */
;      /*  The caller passes in the following parm packet:              */                             */
;      /*                                                               */
;      /*  ULONG  ulRegState                                            */
;      /*         TRUE - register                                       */
;      /*         FALSE - deregister                                    */
;      /*                                                               */
;      /******************* END  OF  SPECIFICATIONS *********************/

IOMW_RG  proc near

       push es
       push bx
       les  bx, es:[bx].GIOParaPack    ; load selector to data area

       mov  eax, dword ptr es:[bx]
       mov  [si].fTaskPtr, eax

       cmp  [si].fBlocked, 0           ; JC - Are we blocked
       jz   justreturn                 ; JC - No, then just return

       mov  bx, ds                     ; JC - Block ID low word
       lea  ax, [si].CursorBlockID     ; JC - Block ID high word
       mov  dl, DevHlp_ProcRun         ; JC - Specify request function number
       call fs:Device_Help             ; JC - Invoke Run Function

justreturn:
       pop  bx
       pop  es
       ret                             ; Return to IOCTL Handler Rtn.

IOMW_RG  ENDP

; GRADD END

;***********************************************************************
;*
;*  FUNCTION NAME:  IOMW_CS    (6Ch)
;*
;*  DESCRIPTION     :  Set the mouse's current constrained region
;*
;*  FUNCTION:  The caller passes in the following data
;*             packet:
;*
;*
;*  USHORT X0;                /* Upper left corner (inclusive) of constraint
;*  USHORT Y0;                /*
;*  USHORT X1;                /* Lower right corner (inclusive) of constraint
;*  USHORT Y1;                /*
;*
;*  ENTRY POINT:  IOMR_CS           LINKAGE:  CALL NEAR
;*
;*  INPUT:  ES:BX points to the request block.
;*          SI has offset to current session control block.
;*
;*  RETURN-NORMAL  :  Always, user address contains requested data.
;*
;*  RETURN-ERROR  :  Never.
;*
;*  EFFECTS:  Stack is clean on return.  Regs not preserved.
;*
;*  INTERNAL REFERENCES:
;*           ROUTINES:  NONE.
;*
;*  EXTERNAL REFERENCES:
;*     ROUTINES:  NONE.
;*     DevHelps:  NONE.
;*
;***********************************************************************

IOMW_CS  proc near

       push es                             ; save es
       push di
       les  di, es:[bx].GIODataPack        ; get address of use area
       mov  ax,es:[di]
       mov  [si].ConstrX0,ax
       mov  ax,es:[di+2]
       mov  [si].ConstrY0,ax
       mov  ax,es:[di+4]
       mov  [si].ConstrX1,ax
       mov  ax,es:[di+6]
       mov  [si].ConstrY1,ax

       mov  cx,[si].Ptr_Row_Pos         ; make sure pointer is currently @131957
       mov  dx,[si].Ptr_Col_Pos         ; in the constrained area        @131957
       call MOVEPTR                     ; move the pointer               @131957


       pop  di
       pop  es                             ; restore es

       ret                                 ; Return to IOCTL Handler Rtn.

IOMW_CS ENDP


;***********************************************************************
;*
;*  FUNCTION NAME:  MOVEPTR           - @131957
;*
;*  DESCRIPTION     :  Move pointer within constrained region.
;*
;*  FUNCTION:
;*
;*  ENTRY POINT:  MOVEPTR           LINKAGE:  CALL NEAR
;*
;*  INPUT:  ES:BX points to the request block.
;*          SI has offset to current session control block.
;*          CX contains desired row position
;*          DX contains desired column position
;*
;*  RETURN-NORMAL  :  Always, user address contains requested data.
;*
;*  RETURN-ERROR  :  Never.
;*
;*  EFFECTS:  Stack is clean on return.  Regs not preserved.
;*
;*  INTERNAL REFERENCES:
;*           ROUTINES:  NONE.
;*
;*  EXTERNAL REFERENCES:
;*     ROUTINES:  NONE.
;*     DevHelps:  NONE.
;*
;***********************************************************************

MOVEPTR proc near
       push     bx
       call DisableMouse          ; Hold Mouse Interrupts
       mov  bl, fs:FgndSessn      ; Get current foreground SG #
       call PtrDrawCheck          ; see if pointer draw op is OK
       .if <ax eq 0>              ; If Not a Ptr Collision
          mov  al, fs:CallSessn   ; Get forground screen group #
          push cx                 ; Save current reg value
          mov  cx, 0              ; Flag Remove Ptr Required
          call RemovePointer      ; Hide Mouse Pointer Image
          pop  cx                 ; Restore previous reg value
       .endif                     ; Collision Area Test

       test [si].MType, Graphics
       .if nz
          .if <dx lt [si].ConstrX0>
             mov     dx,[si].ConstrX0
          .elseif <dx gt [si].ConstrX1>
             mov     dx,[si].ConstrX1
          .endif
          .if <cx lt [si].ConstrY0>
             mov     cx,[si].ConstrY0
          .elseif <cx gt [si].ConstrY1>
             mov     cx,[si].ConstrY1
          .endif
       .endif


       mov  [si].Ptr_Row_Pos, cx  ; Update pointer position
       mov  [si].Ptr_Col_Pos, dx  ; Fields in SG CB
       mov  bl, fs:FgndSessn      ; Get current foreground SG #

       call PtrDrawCheck
       .if <ax eq 0>              ; If Not a Ptr Collision
          mov  al, fs:CallSessn   ; Get forground screen group #
          call DrawPointer        ; Ensure Mouse Ptr is visible
       .endif                     ; New Ptr Collision Test

       call EnableMouse           ; Data Updated, Allow Mouse Ints
       pop      bx
       ret
MOVEPTR ENDP

CSEG2   ENDS
        END
