;/*************************************************************************
;*
;* SOURCE FILE NAME = STRAT.ASM
;*
;* DESCRIPTIVE NAME = Strategy routine, Request routines, and
;*                    IOCtl support.
;*
;* 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         08/30/91
;*
;* DESCRIPTION  This file contains the mouse strategy routine,
;*              request routines, and IOCtl support routines.  See
;*              the linker control file for the location in the link
;*              list.
;*
;* FUNCTIONS
;*              Request_Handler   Mouse Device Driver Request Handler
;*              Req_Err           Request block Error handler routine.
;*              Flush             Input Flush Request handler routine.
;*              Open              Device Open Request handler routine.
;*              Close             Device Close Request handler routine
;*              IOCtl             Generic IOCTL Request handler routine.
;*              DEINS             Deinstallation Request handler routine.
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              Ptr Draw DD, INIT, IOMW_MM, Device
;*                               Dependent DD, Monitor_Handler,
;*                               CollisionChk.
;*              SemRequest, GetDOSVar, SemClear,
;*                               DevDone, DeRegister, MonitorCreate.
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   04/21/93  @V2.1XXX01  67424  Loose mouse when coming back from suspend
;*                                mode on Dell 325nc laptop.
;*   06/03/93  @V2.1XXX02  69671  Lose pointing stick when coming back from
;*                                suspend mode on IBM 700 series laptops.
;**************************************************************************



.xlist
        include mouse.inc
        include infoseg.inc
        include filemode.inc
        include basemaca.inc
        include osmaca.inc
        include emiidc.inc                              ;emi
.list

CPUMODE 386

;*
;*    External Mouse Module Data References
;*

       extrn  Num_Grps                              : byte
       extrn  CallSessn                             : byte
       extrn  FgndSessn                             : byte
       extrn  Ptr_Overide                           : byte
       extrn  DeInstall                             : byte
       extrn  Detach_Proc                           : byte
       extrn  DeviceData                            : byte
       extrn  CurCommand                            : byte
       extrn  CurRequest                            : byte
       extrn  AccessTbl                             : byte
       extrn  TypeOverRider                         : byte
       extrn  SType                                 : byte
       extrn  EmiFlags                              : byte  ; emi
       extrn  APMDD                                 : byte  ; @V2.1XXX01
       extrn  APMIDCDereg                           : byte  ; @V2.1XXX01

       extrn  RBlk_Tbl                              : word
       extrn  Func_Tbl                              : word
       extrn  Sem_PID                               : word
       extrn  CallPID                               : word
       extrn  DDDInit                               : word
       extrn  StratEntry                            : word
       extrn  IntEntry                              : word
       extrn  EMaskMax                              : word
       extrn  APMIDCHandle                          : word  ; @V2.1XXX01
       extrn  SynchFlag                             : word  ; @V2.1XXX02

       extrn  Ctl_Sem                               : dword
       extrn  Sem_Time                              : dword
       extrn  Device_Help                           : dword
       extrn  InfoSegAddr                           : dword

       extrn  FlushMonChain                         : far
       extrn  Mouse_Init                            : far
       extrn  RegisterForAPM                        : far   ; @V2.1XXX01
       extrn  RemovePointer                         : far   ; GRADD
       extrn  TrapDoorAPMResume                     : far   ; CN 4/3/96
       extrn  Monitor_Handler                       : near
       extrn  IOMW_MM                               : near
       extrn  AccessCheck                           : near
       extrn  PDDCMD_MSEEntry                       : near
       extrn  SGControl                             : near
       extrn  GetDeviceParms                        : near
       extrn  EnableMouse                           : near
       extrn  DisableMouse                          : near
       extrn  FindCB                                : near
       extrn  InitSDevice                           : near
       extrn  Emi_Config                            : near      ;emi

       EXTRNFAR CollisionChk


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

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

       public  Request_Handler
       public  RH_Exit
       public  REQ_ERR
       public  FLUSH
       public  OPEN
       public  CLOSE
       public  IOCTL
       public  DEINS
       public  INITCOMPLETE                                 ; @V2.1XXX01


;************************************************************************
;*
;*  FUNCTION NAME :  Request_Handler
;*
;*  DESCRIPTION   :  Mouse Device Driver Request Handler
;*                   Routine.
;*
;*                   Processes requests to the mouse device driver.
;*                   The following requests are valid: Open, Close,
;*                   Flush, Init, DeInstall, and Generic IOCtl.
;*                   All other request are returned with an error code.
;*                   The Init and DeInstall requests are valid only
;*                   during install time.  Each request is handled by
;*                   a separate routine that is called via a call
;*                   table.   When the request is finished, a DevHlp
;*                   call is done to indicate that the request is done.
;*                   Access to the Request_Handler is serialized with
;*                   a RAM semaphore, with the exception of a close
;*                   request.semaphore ownership is at the process
;*                   level.
;*
;*  NOTES         :  All requests use the generic device request packet
;*                   format.  Generic IOCtls use the function specific
;*                   data area to pass specific parameters to indiviual
;*                   IOCtl routines.  SI contains the offset to the
;*                   session control block for the calling session.
;*
;*  ENTRY POINT   :  Request_Handler    (PROTECT MODE ONLY)
;*     LINKAGE    :  CALL FAR
;*
;*  INPUT         :  ES:BX points to the request packet.
;*
;*  RETURN-NORMAL :  Request Block status field set to indicate
;*                   function complete, no error.
;*
;*  RETURN-ERROR  :  Error codes set in Request Block status field.
;*
;*  EFFECTS       :  Stack is clean on return, Registers not preserved.
;*
;*  INTERNAL REFERENCES:
;*     ROUTINES:  Mouse_Init, Open, Close, Flush, Ioctl, Deins,
;*                Req_Err
;*
;*  EXTERNAL REFERENCES:
;*     ROUTINES: DDDD(Read_Enable, Query_Config, Enable_Device)
;*     DevHlps:  SemRequest, GetDOSVar, SemClear, DevDone.
;*
;*************************************************************************
;* PSEUDOCODE :
;*
;* BeginSub  REQUEST_HANDLER
;*
;* IF <IDC initialization is required>
;*    call GetDeviceParms to do the IDC initialization
;* ENDIF
;*
;* IF <Mouse DD initialized AND NOT deinstalled> THEN
;*    IF <NOT CLOSE command> THEN
;*       Call Device_Help(SemRequest) to get mouse semaphore
;*    ELSE
;*       set flag to show SemRequest worked
;*    ENDIF
;*
;*    IF <SemRequest worked>
;*       Call Device_Help(GetDOSVar)
;*       IF <GetDOSVar worked> THEN
;*          set calling session to session # in LDT
;*          IF <procedure type is DETACHED> THEN
;*             set calling session # to VIO pop up session
;*             set detached flag on
;*          ELSE
;*             set detached flag off
;*             IF <VIO Windowable OR PresMGR app> THEN
;*                set calling session # to shell session
;*             ENDIF
;*             IF <NOT Fullscreen App AND NOT Detached App> THEN
;*                set request error in req block
;*             ELSE
;*                IF <command is valid> THEN
;*                   IF <IDC interface is initialized OR
;*                       command is OPEN               OR
;*                       command is CLOSE>
;*                      call requested command service routine
;*                   ELSE
;*                      set DeviceNotReady error in Req Block
;*                   ENDIF
;*                ELSE
;*                   Call Req_Err
;*                ENDIF
;*             ENDIF
;*
;*          ENDIF
;*       ELSE                                     * GetDOSVar Failed
;*          GenFail
;*       ENDIF
;*
;*    IF <NOT CLOSE command> THEN
;*       Call Device_Help(SemClear) to release the semaphore
;*    ENDIF
;*
;* ELSE                                        * mouse not initialized
;*
;*    IF <INIT Command> THEN
;*       Call Mouse_Init to initialize
;*    ELSE
;*       Call Req_Err
;*    ENDIF
;*    call Device_Help(DevDone) to show done with request packet
;* ENDIF
;* return
;*
;*EndSub  REQUEST_HANDLER
;*
;***********************************************************************

Request_Handler  proc  far

       ?frame = 0
       LocalVar   TempES, WORD                ; Setup local stack frame
       Localvar   TempBX, WORD

       EnterProc

       inc  StratEntry                        ; show we have entered strategy rtn
       mov  TempES, ES                        ; Save Request Block Address
       mov  TempBX, BX
       mov  al, es:[bx].PktCmd                ; get current command
       mov  CurCommand, al                    ; save for debugging

;*
;*     If this is the 1st level 0 call then we must initialize the
;*     interface with the device dependent DD.  This cannot be done at
;*     init time because initialization is at level 3 and the entry
;*     points, returned by AttachDD, to the DDDD are ring 0. For this
;*     reason the Query_Config and Read_Enable calls are done now.  If
;*     either fail then we will shut down as if we were deinstalled.
;*

       .if <bit DDDInit nz DI_IDC>            ; if IDC initialization needed
         .if <TypeOverRider eq TRUE>
            call GetDeviceParms               ; go get device data
         .endif

         .if <SType eq TRUE>
            call InitSDevice
         .endif
       .endif

;*
;* Do emi configuration after device dependent so that emi can fix things  ;emi
;* up if there is no base mouse device so that the mouse driver still works;emi
;* for the emi devices.                                  ;emi
;*

       .if <bit EmiFlags nz EMI_NEED_CONFIG>  ; emi configuration needed  ;emi
          call Emi_Config                               ;emi
       .endif                                           ;emi
;*
;*      If the mouse has be intialized and has not been deinstalled then
;*      it is OK to continue.
;*

       .if <<word ptr Device_Help+2> ne 0> NEAR AND
       .if <Deinstall eq OFF> near

;*
;*         If this request is a close request then do not request the
;*         semaphore. This is because the process could have died owning the
;*         semaphore.  The close is part of cleaning up old semaphores.
;*

          .if <es:[bx].PktCmd ne CMDClose>  ; If not a Close Request then

;*
;*            Use DEVHELP (SemRequest) to synchronize request processing
;*

             mov  bx, OFFSET Ctl_Sem         ; High word of Sem addr

             mov  ax, ds                     ; Low word of Sem addr
             mov  cx, word ptr Sem_Time      ; Low word of Timeout value
             mov  di, word ptr Sem_Time+2    ; High word of Timeout value
             mov  dl, DevHlp_SemRequest      ; Specify function number
             call Device_help                ; Invoke SemRequest function
          .else                              ; if a close request then
             clc                             ; setup common "good" path result
          .endif                             ; close request test
                                             ;
          .if nc near                        ; if SemRequest worked then

                les  bx,InfoSegAddr
                mov  dx, es                  ; Save LDT InfoSeg Selector
                mov  cx, bx                  ; Put Offset into CX

                mov  ax, es:[bx].LIS_CurScrnGrp     ; Get LDT SG ID
                mov  CallSessn, al                  ; Save LDT SG ID
                mov  AX, es:[bx].LIS_CurProcID      ; Get LDT PID
                mov  CallPID, ax                    ; Save Proc ID

                mov  ah, es:[bx].LIS_ProcType       ; Get LDT Proc Type

                .if <ah eq LIS_PT_DETACHED>         ; If a Detached Process
                   mov  CallSessn, VIO_PopUp_SG     ; Setup PopUp SG ID #
                   mov  Detach_Proc, ON             ; Set Detached Proc Flag
                .else                               ; If not a Detached Proc
                   mov  Detach_Proc, OFF            ; Reset Detached Proc Flag
                   .if <ah eq LIS_PT_VIOWIN> OR     ; If Vio windowable app
                   .if <ah eq LIS_PT_PRESMGR>       ; or Present. Mgr app.
                      mov  ah, LIS_PT_FULLSCRN      ; Map proc type and SG#
                      mov  CallSessn, Shell_Session ; to Winthorn session
                   .endif                           ; End extended SG test
                .endif                              ; Detached Process Tests

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

                .if <es:[bx].PktCmd ne CMDClose>    ; If not a Close Req then
                   mov  cx, CallPID                 ; Copy LDT PID as
                   mov  Sem_PID, cx                 ; Semaphore owner
                .endif                              ; Close Request Test

; GRADD HACK ABOVE
                .if <ah eq LIS_PT_REALMODE>         ; If not a Full Scrn App
                   jmp  graddhack
                .endif
; GRADD HACK BELOW

                .if <ah ne LIS_PT_FULLSCRN> AND     ; If not a Full Scrn App
                .if <ah ne LIS_PT_DETACHED>         ; And Not A Detached App
                   mov  es:[bx].PktStatus, UNKNOWNCMD
                .else  near                         ; If Protect Mode req
                   mov  al, es:[bx].PktCmd          ; Get Req Blk Cmd Code
                   xor  ah, ah                      ; clear ah
                   .if <al b RBlk_Min> OR           ; If Command Code is
                   .if <al a RBlk_Max>              ; Invalid  then
                       .if <al eq CMDSaveRestore>   ; Save/restore command?
                           call TrapDoorAPMResume
                       .else
                           mov  es:[bx].PktStatus, UNKNOWNCMD
                       .endif
;*
;*        The request is within the valid range.  Now check to see
;*        that the IDC to the dependent DD was initialized and/or
;*        support was not disabled by the dependent DD.  If the
;*        IDC has been shut down then still allow opens and closes,
;*        otherwise fail the request with a DEVICENOTREADY error.
;*

                   .else                             ; Else Command Code Valid
                      .if <bit DDDInit nz DI_ERROR> AND    ; IDC Init error ?
                      .if <al ne CMDOpen> AND        ; and not an open or
                      .if <al ne CMDClose>           ; close then
                         mov  es:[bx].PktStatus, DEVICENOTREADY
                      .else                          ; else request is OK

;*
;*        If the request is a category Bh, function 41h IOCtl
;*        then the request is a screen group control request.
;*        In this case do not load DS:SI with the CB address
;*        because it may not exist.  It will be loaded later
;*        if needed.  If it is some other request then load
;*        DS:SI with the CB address for the calling session.
;*        In either case FS is loaded with the mouse data
;*        segment.  FS should be used by any routines that
;*        are below the Request_Handler.
;*

                         push ds                   ; save ds
                         push fs                   ; and fs
                         push ds                   ; put ds in fs
                         pop  fs

                         mov  di, ax               ; put function code
                         shl  di, 1                ; in di and shift

                         .if <al eq CMDGenIOCTL> and
                         .if <es:[bx].GIOCategory eq 0bh> and
                         .if <es:[bx].GIOFunction eq 41h>
                            call SGControl         ; call screen group control
                         .else
                            push bx
                            xor  bh, bh
                            mov  bl, CallSessn     ; get CB of call sessn
                            call FindCB
                            pop  bx
                            .if <nc>               ; if CB found
                               call fs:RBlk_Tbl[di]; call requested routine
                            .else                  ; else, set a
                               GenFail             ; general failure error
                            .endif
                            mov  bx, TempBX        ; restore BX
                         .endif
                         pop  fs                   ; restore fs
                         pop  ds                   ; restore ds
                      .endif
                   .endif                          ; end valid req test

                .endif                             ; Req Mode tests


             .if <es:[bx].PktCmd ne CMDClose>  ; If not a Close Request then

;*
;*        Use DEVHLP (SemClear) to free the process control Semaphore
;*

                mov  bx, OFFSET Ctl_Sem       ; High word of sem address

                mov  ax, ds                   ; Low word of sem address
                mov  dl, DevHlp_SemClear      ; Devhelp function number
                call Device_Help              ; Invoke SemClear function
                mov  Sem_PID, 0000H           ; Clear Sem ownership PID
             .endif                           ; Close Request Test

          .else                               ; If SemRequest failed then
             GenFail                          ; Set General Failure Return Code
          .endif                              ; SemRequest Tests

graddhack:
          mov  bx, TempBX                     ; Restore Request Block Address

;*
;*         use DEVHLP (DevDone) to wrap up request block processing
;*

          mov  dl, DevHlp_DevDone             ; Specify function number
          call Device_help                    ; Invoke DevDone Function

       .else                                  ; If DD is not init'd or it's
                                              ; Been DeInstalled then
          mov  al, es:[bx].PktCmd             ; Get Req Blk Cmd Code

          .if <al eq CMDInit>                 ; If an INIT Request then
             call Mouse_Init                  ; Invoke Initialization Rtn
          .else                               ; If not an INIT Request then
             .if <DeInstall eq ON>            ; if we have deinstalled
                mov  es:[bx].PktStatus, UNKNOWNCMD
             .endif
          .endif                              ; INIT Req Tests

          or   es:[bx].PktStatus, STDON       ; Set Req Blk Complete Flag

       .endif                                 ; DD Initialization tests

       LeaveProc                              ; Clear stack frame
       dec  StratEntry                        ; decrement debug aid

RH_Exit:

       ret                                    ; Return to caller

Request_Handler  ENDP


;************************************************************************
;*
;*  FUNCTION NAME :  Req_Err
;*
;*  DESCRIPTION   :  Request block Error handler routine.
;*
;*                   This routine sets the request block status field
;*                   to the error code UNKNOWN COMMAND.  The request
;*                   block is pointed to by ES:BX.
;*
;*  ENTRY POINT   :  Req_Err                    LINKAGE:  CALL NEAR
;*
;*  INPUT         :  ES:BX points to the request block.
;*
;*  RETURN-NORMAL :  Error return code set within Request Block
;*                   status field.           (Always)
;*
;*  RETURN-ERROR  :  N/A
;*
;*  EFFECTS       :  Stack is clean on return, NO registers changed.
;*
;*
;*************************************************************************
;*
;* BeginSub  REQ_ERR
;*
;*  set packet status in request block to UNKNOWN COMMAND
;*  return
;*
;* EndSub  REQ_ERR
;*
;***********************************************************************

REQ_ERR  proc  near

;*
;*      Set Request Block bits 15 and 3 for an Unknown Command Error
;*

       mov  es:[bx].PktStatus, UNKNOWNCMD
       ret
REQ_ERR  endp


;************************************************************************
;*
;*  FUNCTION NAME :  Flush  (07H, Input Flush Cmd)
;*
;*  DESCRIPTION   :  Input Flush Request handler routine.
;*
;*                   Flushes the session monitor chain and event que.
;*                   All events are discarded by the monitor handler
;*                   until it receives the flush record.   If singleQ
;*                   mode is active for the session, then an UNKNOWN
;*                   COMMAND error is returned.
;*
;*  ENTRY POINT   :  Flush                          LINKAGE: CALL NEAR
;*
;*  INPUT         :  ES:BX Points to the request block.
;*                   SI has offset to current session's control block
;*
;*  RETURN-NORMAL :  Caller's screen group event queue and Monitor
;*                   Chain are flushed.
;*
;*  RETURN-ERROR  :  Error return code value set in Request block
;*                   Status field.
;*
;*  EFFECTS       :  Stack is clean on return, registers not preserved.
;*
;*  INTERNAL REFERENCES:
;*     ROUTINES:  FlushMonChain, Req_Err
;*
;*************************************************************************
;* PSEUDOCODE :
;*
;*BeginSub  FLUSH
;*
;* IF <NOT a Detached Process> THEN
;*    IF <SingleQ mode not active> THEN
;*       disable system ints
;*       IF <Device NOT busy> THEN
;*          call FlushMonChain to flush the event queue and mon chain
;*          IF <DevHlp_MonFlush FAILED> THEN
;*             set general failure error
;*          ENDIF
;*       ELSE
;*          set general failure error
;*       ENDIF
;*       enable system ints
;*    ELSE
;*       set request error
;*    ENDIF
;* ELSE
;*    set request error
;* ENDIF
;* Return
;*
;*EndSub  FLUSH
;*
;***********************************************************************

FLUSH  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

;*
;*      If the process is not a detached process then the flush is done.  If
;*      the session has singleq mode active then the flush is rejected as an
;*      unknown command error.  If not then the request is processed.
;*

       .if <fs:Detach_Proc eq OFF> near       ; If Not Detached Process
          test [si].D_Status, SQ_Mode         ; Check SQ Mode Flag Bit
          .if <z> near                        ; If SQ Mode InActive
             cli                              ; Hold ints for queue update

;*
;*     If the queue is busy with activity then reject the flush with a
;*     general failure error, otherwise process the flush request.
;*

             test [si].D_Status, Busy_Mask    ; Check Que Busy Flag Bit
             .if <z> near                     ; If Event Que not busy with I/O
                call FlushMonChain            ; go flush the chain
                .if c                         ; If MonFlush failed then
                   and  [si].D_Status, NOT Q_Flush  ; Reset Flush Flag Bit
                   GenFail                    ; Set Request Block Error code
                .endif                        ; MonFlush Completion Flag

                and  [si].D_Status, NOT Busy_Mask  ; Reset Que Busy Flag

             .else                            ; If SG Event Queue is busy then
                GenFail                       ; Set Request Block Error code
             .endif                           ; Event Queue Busy test
             sti                              ; Que reset done, allow interrupts
          .else                               ; If SQ Input Mode is Active
             mov  es:[bx].PktStatus, UNKNOWNCMD
          .endif                              ; SQ Input Mode Tests

       .else                                  ; If a Detached Process Then
          mov  es:[bx].PktStatus, UNKNOWNCMD
       .endif                                 ; Detached Process Tests

       LeaveProc

       ret                                    ; Return to Request_Handler Rtn.
FLUSH  ENDP



;************************************************************************
;*
;*  FUNCTION NAME :  Open
;*
;*  DESCRIPTION   :  Device Open Request handler routine.
;*
;*                   This routine processes Open requests.  It updates
;*                   the calling session's active handle counter.  If
;*                   the counter increments from 0 to 1 then the
;*                   session's control block is initialized.  The
;*                   initialized state is the following:
;*                      Row/Col Scale factors = 16:8
;*                      All events reportable
;*                      Monitor chain and event queue flushed
;*                      If Valid mode data available set:
;*                         Ptr position to center of screen
;*                         Define display space as collision area
;*                      If no mode data available set:
;*                         Ptr to (0,0)
;*                         Collision area to (0,0) - (32K, 32K)
;*                      Device status is set to:
;*                         Ptr Draw DD is called for ptr operations
;*                         report display coordinate movement
;*
;*  ENTRY POINT   :  Open                        LINKAGE:  CALL NEAR
;*
;*  INPUT         :  ES:BX points to the request block.
;*                   SI has offset to current session's control block
;*
;*  RETURN-NORMAL :  Caller's session handle counter is incremented
;*                   and session initialized if level 1 open.
;*
;*  RETURN-ERROR  :  Error return code is set in the Request block
;*                   Status field.
;*
;*  EFFECTS       :  Stack is clean on return, AX, CX, DX, and DI
;*                   register contents are destroyed.
;*
;*  INTERNAL REFERENCES:
;*     ROUTINES:  Req_Err.
;*
;*  EXTERNAL REFERENCES:
;*     ROUTINES:  Ptr Draw(FreePointerMem), DDDD(Disable_Device,
;*                Enable_Device)
;*
;************************************************************************
;*
;*BeginSub  OPEN
;*
;*   Call DDDD(Disable_Device) to disable the mouse
;*
;*   IF <session hs no open handles>
;*      RowScale_Fact <- 16
;*      ColScale_Fact <- 8
;*      Row_Remain <- 0
;*      Col_Remain <- 0
;*      Col_Cell_Remain <- 0
;*      Row_Cell_Remain <- 0
;*      Calculate max event mask using number of buttons
;*      reset settable bits in device status flags
;*      reset block bit in device status flags
;*      Event_Q_Size <- 0
;*      EQ_Head <- start of event queue
;*      EQ_Tail <- EQ_Head
;*      Define collision area (area flags <- 1)
;*      Area_Top <- 0
;*      Area_Left <- 0
;*
;*      IF <mode data not available>
;*         set unsupported mode in device status
;*         set pointer position to (0,0)
;*         Area_Bot <- 7fffh
;*         Area_Right <- 7fffh
;*
;*      ELSE
;*
;*         IF <current mode is graphics>
;*            enable threshold calculations
;*            use graphics resolutions
;*         ELSE
;*            disable threshold calculations
;*            use text resolutions
;*         ENDIF
;*
;*         Area_Bot <- max vertical resolution
;*         Area_Right <- max horizontal resolution
;*         set pointer to center of screen (1/2 resolutions)
;*
;*      ENDIF
;*
;*      IF <pointer draw DD registered>
;*         call PointDD(FreePointerMem) to free buffers
;*      ENDIF
;*
;*      IF <Device resolution is above 100 mickeys/inch>
;*         threshold_1 <- 10
;*         threshold_2 <- 20
;*      ELSE
;*         threshold_1 <- 5
;*         threshold_2 <- 10
;*      ENDIF
;*
;*   ENDIF   /*  1st level open
;*
;*   increment session open handle counter
;*   call DDDD(Enable_Device) to enable the mouse
;*
;*EndSub  OPEN
;*
;***********************************************************************

OPEN  PROC  NEAR

       call DisableMouse               ; Hold Mouse Interrupts

       mov  ax, [si].Hdle_Cntr         ; Get SG CB open handle counter
       .if <ax eq 0> NEAR              ; If SG is Opening then

;*
;*         Initialize the session control block to default values.
;*

          mov  [si].RowScale_Fact, 16   ; Load default
          mov  [si].ColScale_Fact, 8    ; Scaling Factors
          mov  [si].Row_Remain, ax      ; Clear Row remainder
          mov  [si].Col_Remain, ax      ; Clear Col remainder
          mov  [si].Col_Cell_Remain, ax ; Clear Col pixel remainder
          mov  [si].Row_Cell_Remain, ax ; Clear Row pixel remainder

          mov  bx, fs:EMaskMax          ; invert to make valid events 1's
          mov  [si].E_Mask, bx          ; All events are queueable

          mov  cx, [si].D_Status        ; Get current Status Flags
          xor  ch, ch                   ; Clear Settable Flags
          and  cl, NOT Block_Mask       ; clr blocked bit
          mov  [si].D_Status, cx        ; Restore Dev Status Flags

;*
;*         Set the event queue to empty and define the session colision area
;*         as the entire screen.
;*

          mov  [si].Eq_Size, al            ; Set Queue empty count
          mov  cx, [si].E_Queue            ; Get event que base offset
          mov  [si].Eq_Head, cx            ; Queue algorithm ptr
          mov  [si].Eq_Tail, cx            ; Mem offset positions

          mov  [si].Area_Flags, 0001H      ; Define Collision Area
          mov  [si].Area_Top, ax           ; Define full screen
          mov  [si].Area_Left, ax          ; Collision Area

          mov  [si].Lvl1Mplr, 2            ; 2x at 1st level (Default
          mov  [si].Lvl2Mplr, 4            ; 4x at 2nd level     Multipliers)

          mov  cx, [si].MLength            ; Get current mode data len
          .if <cx eq 0>                    ; If No Disp Mode Data then
             mov  [si].D_Status, ax        ; Init Device Status Flags
             or   [si].D_Status, USS_Mode  ; Set Bad Display Mode Flag Bit
             mov  [si].Ptr_Row_Pos, ax     ; Set Ptr at upper left
             mov  [si].Ptr_Col_Pos, ax     ; Until Mode is set
             mov  [si].Area_Bot, 07fffh    ; Define it to be bigger than
             mov  [si].Area_Right, 07fffh  ; Current default Disp Modes

          .else                            ; If Disp Mode data avail

             test [si].MType, Graphics     ; Check current Display Mode
             .if  nz                       ; If in Graphics Mode then
                mov  cx, [si].GRow_Res     ; Get row resolution
                mov  bx, [si].GCol_Res     ; Get col resolution
             .else                         ; If in Text Mode then
                mov  cx, [si].TRow_Res     ; Get row resolution
                mov  bx, [si].TCol_Res     ; Get col resolution
             .endif                        ; Display Mode Tests

            .if <cx gt 640> OR             ; if high resolution change
            .if <bx gt 480>                ;   thresholding multipliers
                mov  [si].Lvl1Mplr, 3      ; 3x at 1st level
                mov  [si].Lvl2Mplr, 6      ; 6x at 2nd level
            .endif


             mov  [si].Area_Bot, cx        ; Full Screen Collision Area
             mov  [si].Area_Right, bx      ; = Display Mode Resolution
             shr  cx, 1                    ; Get half row resolution
             mov  [si].Ptr_Row_Pos, cx     ; For center screen ptr pos
             shr  bx, 1                    ; Get half col resolution
             mov  [si].Ptr_Col_Pos, bx     ; For center screen ptr pos
          .endif                           ; Disp Mode Data Test

;*
;*         Call the session registered pointer draw, if there is one, to
;*         set the pointer to the default.  Then set the default threshold
;*         (acceleration) levels according to the mouse device sesitivity.
;*

          .if <<word ptr [si].Screen_Entp+2> ne 0> ; If SG PointDD dfnd
             mov  al, fs:CallSessn                 ; Get FG SG ID #, reset ptr
             FreePointerMem                        ; To PointDD Mode defaults
          .endif                                   ; Defined PointDD Tests

          .if <fs:DeviceData.NumMics a 40h> ; If a higher resolution mouse
             mov  [si].Level1, 3                   ; then set the higher res
             mov  [si].Level2, 20                  ; threshold defaults.
          .else                             ; Otherwise if a lower res mouse
             mov  [si].Level1, 5                   ; then set the loser res
             mov  [si].Level2, 10                  ; threshold defaults.
          .endif

       .endif                                      ; session itialization test

       inc  [si].Hdle_Cntr                         ; Update SG Handle Counter
       call EnableMouse                            ; Allow Mouse Interrupts
       ret                                         ; Return to Request Handler Rtn.

OPEN  ENDP


;************************************************************************
;*
;*  FUNCTION NAME :  Close
;*
;*  DESCRIPTION   :  Device Close Request handler routine.
;*
;*                   This routine processes two types of close
;*                   requests.                   They are
;*
;*                   1.  Device close - This request decrements the
;*                       session's active handle counter.  If the
;*                       counter decrements to 0 then support for that
;*                       session is closed, the monitor chain is
;*                       flushed, and the pointer is removed.
;*
;*                   2.  Monitor close - This request deregisters all
;*                       monitors for the process regardless of the
;*                       session the monitor was registered for.
;*
;*  ENTRY POINT   :  Close          LINKAGE:  CALL NEAR
;*
;*  INPUT         :  ES:BX points to request block.
;*                   DS:SI has offset to current session's control block.
;*
;*  RETURN-NORMAL :  Caller's screen group handle counter is
;*                   decremented.
;*
;*  RETURN-ERROR  :  Error return code set in Request Block Status
;*                   field.
;*
;*  EFFECTS       :  Stack is clean on return, AX, CX, DX, and SI
;*                   register contents are destroyed.
;*
;*  INTERNAL REFERENCES:
;*     ROUTINES:  CollisionChk, FlushMonChain.
;*
;*  EXTERNAL REFERENCES:
;*     ROUTINES:  Ptr Draw(RemovePointer), DDDD(Enable_Device,
;*                Disable_Device)
;*     DevHlps:   SemClear, DeRegister.
;*
;*************************************************************************
;*
;*BeginSub  CLOSE
;*
;* decrement session open handle
;* IF <Hdle_Cntr = 0> THEN                        * Session closing
;*    call DDDD(Disable_Device) to disable the mouse
;*    IF <Ptr Draw Enabled                          AND
;*        display mode supported   AND
;*        pointer draw registered  AND
;*        there is no collision> THEN
;*       call Ptr Draw(RemovePointer) for unconditional ptr remove
;*    ENDIF
;*
;*    call FlushMonChain to flush the monitor chain and event queue
;*    IF <monitor flush failed>
;*       set general failure error
;*    ENDIF
;*
;*    call DDDD(Enable_Device) to enable the mosue
;* ENDIF                                         * Session closing
;*
;* IF <Monitor Close request> THEN
;*    WHILE <more sessions>
;*       IF <Registered monitor> THEN
;*          call Device_Help(DevHlp_DeRegister(Chain_Hdle,Proc_ID)
;*          IF <DeRegister FAILED> THEN
;*             set general failure error code
;*          ELSE
;*             set session chain size to what's left
;*          ENDIF
;*       ENDIF
;*    ENDWHILE
;* ENDIF
;*
;* IF <Caller owns Device Semaphore> THEN
;*    call Device_Help(DevHlp_SemClear) to release it
;*    IF <Blocked thread AND Blocked thread is closing PID> THEN
;*       reset blocked thread status
;*    ENDIF
;* ENDIF
;* Return
;*
;*EndSub  CLOSE
;*
;***********************************************************************

CLOSE  PROC  NEAR

       ?frame = 0                           ; Define local stack frame
       LocalVar TempES, WORD
       LocalVar TempBX, WORD
       LocalVar TempSI, WORD                ; Alloc Stack Space for SI
       LocalVar TempFS, WORD                ;

       EnterProc
       mov  TempFS, fs                      ; Save Base Mouse Data Sel
       mov  TempES, es                      ; Save Request Block address
       mov  TempBX, bx
       mov  TempSI, si                      ; Save Current SG CB Offset


       and  [si].Ptr_Flags, NOT SM_WinFlag  ; Reset Set Mode Disable Flag
       dec  [si].Hdle_Cntr                  ; Update SG open handle counter

;*
;*      If a session is closing, ie. open handle count going to 0, then
;*      perform session clean up.  This consists of removing the pointer and
;*      flushing the monitor chain.
;*

       .if <z> near                           ; If SG support is closing then

         call DisableMouse                    ; Hold Mouse Interrupts
         mov  bl, fs:FgndSessn                ; Get forground screen group #

         test [SI].D_Status, PtrDraw+USS_Mode ; Try PtrDD/Disp Mode Flags
         .if <z> AND                          ; If Ptr DD Used & Mode AOK
         .if <fs:CallSessn eq bl> AND         ; And if process is in FG SG and
         .if <<word ptr [si].Screen_Entp+2> ne 0> ; Ptr draw initialized
           CALLFAR CollisionChk               ; Collision Area Checking
           .if <ax eq 0>                      ; If Not a Ptr Collision
             mov  al, fs:FgndSessn            ; Get forground screen group #
             push cx                          ; Save current reg value
             mov  cx, 0                       ; Flag Remove Ptr Required
             call RemovePointer               ; Hide Mouse Pointer Image (GRADD)
             pop  cx                          ; Restore previous reg value
           .endif                             ; Collision Area Test
         .endif                               ; Valid Hide Ptr Tests

;*
;*        Now go flush the monitor chain.  This will also clear the event queue.
;*

         call FlushMonChain                   ; flush the mon chain and Event Q

         .if <c>                              ; If FlushMonChain failed then
           GenFail                            ; set a general failure return code
         .endif

         call EnableMouse                     ; Allow Mouse Interrupts

       .endif                                 ; SG Closing Test

       mov  bx, TempBX                        ; Restore RB Offset
       test es:[bx].PktStatus, OPEN_MONITOR   ; Check Monitor Bit
       .if <nz> near                          ; If a MonOpen request

         mov  es:[bx].PktStatus, 0            ; Clear Req Blk Status Flags
         xor  bx, bx                          ; Setup SG ID Counter


         .while <bl lt fs:Num_Grps>           ; Loop thru all SG's

           mov  ds, TempFS                    ; Get base Mouse data seg

           call FindCB                        ; Returns pointer to CB
           .if <nc>                           ; If CB found

              mov  al, [si].Chain_Size        ; Get SG Installed Monitor Count
              .if <al a 0>                    ; If SG Monitors Installed
                push bx                       ; Current SG being processed.
                mov  bx, fs:CallPID           ; Set up LDT PID
                mov  ax, [si].Chain_Hdle      ; Get SG CB Chain Handle
                mov  dl, DevHlp_DeRegister    ; Specify Dev_Help Function number
                call fs:Device_Help           ; Invoke DeRegister function
                mov  fs, TempFS               ; Get base Mouse data seg

                .if c                         ; If DeRegister failed then
                  GenFail                     ; Set Req Blk Error Return code
                .else                         ; If nc, AX = # Monitors
                  mov  [si].Chain_Size, al    ; Left in SG Mon Chain
                  .if <zero al>               ; If no more monitors in the chain
                     mov  ax,[si].Chain_Hdle  ; Specify Create Chain
                     add  si, MB_Len          ; add in offset to MOB
                     push ds                  ; SG CB selector
                     pop  es                  ; SG CB selector
                     push cs                  ; Setup DS:DI to Mon
                     pop  ds                  ; Notify Rtn Address
                     mov  di, offset Monitor_Handler
                     mov  dl, DevHlp_MonitorCreate
                     mov  fs, TempFS
                     call fs:Device_Help     ; Invoke MonitorCreate
                     mov  fs, TempFS         ; Get base Mouse data seg
                  .endif
                .endif                       ; DeRegister Tests
                pop  bx                      ; Get last SG # back.
              .endif                         ; Installed Monitors Test

           .endif

           inc  bl                           ; Update SG Index Counter
         .endwhile                           ; SG Mon DeReg Loop

         mov  si, TempSI                     ; Restore Current SGCB Offset
       .endif                                ; DosMonClose Test

       mov  bx, fs:CallPID                   ; Get Callers PID

;*
;*      If process that is doing the close owns the DD semaphore then
;*      use DEVHLP (SemClear) to free the semaphore.
;*

       .if <fs:Sem_PID eq bx>                ; If Closing PID owns DD Sem
          mov  bx, OFFSET Ctl_Sem            ; High word of sem address
          mov  ax, ds                        ; Low word of sem address
          mov  dl, DevHlp_SemClear           ; Specify function number
          call fs:Device_Help                ; Invoke SemClear Function

          mov  cx, fs:Sem_PID                ; Get LDT PID

          test [si].d_status, Block_Mask     ; Check Blocked Thread Flag
          .if <nz> AND                       ; If a thread Blocked and
          .if <cx eq [si].Eq_PID>            ; the thread is Closing then
             and  [si].D_Status, NOT Block_Mask ; Reset Blocked Flag Bit
             mov  [si].Eq_PID, 0000H         ; Clear Eq ownership PID
         .endif                              ; Blocked Event Que Test

         mov  fs:Sem_PID, 0000H              ; Clear Main Sem Ownership PID

       .endif                                ; Dead PID Test

       mov  bx, TempBX                       ; Restore request block addr
       mov  es, TempES
       LeaveProc
       ret                                   ; Return to Request_Handler Rtn.

CLOSE  ENDP



;************************************************************************
;*
;*  FUNCTION NAME :  IOCtl
;*
;*  DESCRIPTION   :  Generic IOCTL Request handler routine.
;*
;*                   This routine is the router for generic IOCtl
;*                   requests.  IOCtl request are routed by using a
;*                   function table.  Invalid requests are handled by
;*                   calling Req_Err to set the error code.  If the
;*                   MODE=R option was specified then only a subset of
;*                   IOCtls are allowed.  These are necessary for
;*                   operation of the 3xBox.
;*
;*  ENTRY POINT   :  IOCtl     LINKAGE:  CALL NEAR
;*
;*  INPUT         :  ES:BX points to the Request block.
;*                   SI has offset to current session's control block.
;*
;*  RETURN-NORMAL :  Requested function completed.
;*
;*  RETURN-ERROR  :  Request Block status field updated with
;*                   appropriate error return code.
;*
;*  EFFECTS       :  Stack is clean on return.
;*
;*  INTERNAL REFERENCES:
;*     ROUTINES:  Req_Err, IOMW_SM, IOMW_SN, IOMW_SS, IOMW_EM,
;*                IOMW_TH, IOMW_PS, IOMW_DP, IOMR_GV, IOMW_SP,
;*                IOMR_NB, IOMR_MC, IOMR_GS, IOMR_RD, IOMR_QS,
;*                IOMR_GM, IOMR_GF, IOMR_GP, IOMR_PS, IOMR_TH,
;*                IOMW_SC, IOMW_MM, IOMW_MD, AccessCheck
;*
;*  EXTERNAL REFERENCES:
;*     ROUTINES:  NONE.
;*
;************************************************************************
;*
;*BeginSub  IOCTL
;*
;* IF <Category is mouse category> THEN
;*    IF <Function out of range                     OR
;*        Request from detached process> THEN
;*       set request error
;*    ELSE
;*       call AccessCheck to check access to user data areas
;*       IF AccessCheck passed
;*          call requested support routine
;*       ELSE
;*          set request error
;*       ENDIF
;*    ENDIF
;* ELSEIF <Category is monitor control> THEN
;*    IF <Function is register a monitor>
;*       call IOMW_MM to register the monitor
;*    ELSE
;*       set request error
;*    ENDIF
;* ELSEIF <Category is general> THEN
;*    IF <function is Query Monitor support AND
;*        NOT a detached process > THEN
;*       set packet status to monitors supported
;*    ELSE
;*       set request error
;*    ENDIF
;* ELSE   /* IOCtl not recognized as supported
;*    set request error
;* ENDIF
;*
;* Return
;*
;*EndSub  IOCTL
;*
;***********************************************************************

IOCTL  PROC  NEAR
         ASSUME    CS:CSEG2, SS:nothing, ES:nothing, DS:nothing

       mov  ah, es:[bx.GIOcategory]        ; Get Request Block Category code
       mov  al, es:[bx.GioFunction]        ; Get Request Block Function code
       mov  fs:CurRequest, al              ; save current IOCtl request code

       .if <ah eq Mou_Cat>                 ; If a Mouse IOCtl then

          .if <al lt Func_LReq_Start> OR   ; If an invalid Mouse function
          .if <al gt Func_HReq_End>   OR   ; Is requested or if a Detached
          .if <fs:Detach_Proc eq ON>       ; Process Request then

             mov  es:[bx].PktStatus, UNKNOWNCMD

          .else                            ; If a valid Mouse Function then
                                           ; Calc call table index as:
             sub  al, Func_LReq_Start      ; Get relative base table index
             cbw                           ; Get it as a word value
             call AccessCheck              ; check access
             .if <nc>                      ;
                shl  ax, 1                 ; Get byte index as word table index
                mov  di, ax                ; Setup DI will call table index
                call word ptr fs:Func_Tbl[di] ; Invoke Requested Function Rtn.
             .else
                ParmErr                    ; otherwise a parameter error
             .endif

          .endif

       .elseif <ah eq Mon_Cat>             ; If a Monitor Request then

          .if <al eq Req_MM>               ; If Monitor Register request then
             call IOMW_MM                  ; Invoke Monitor Register Rtn.

          .else                            ; If not Mon Reg request then
             mov  es:[bx].PktStatus, UNKNOWNCMD
          .ENDIF                           ; Mon_Cat Function Support Tests

       .elseif <ah eq Gen_Cat>             ; If a General DD Category Req

          .if <al eq QMonSup>    AND       ; If Query Mon Support IOCTL
          .if <fs:Detach_Proc eq OFF>      ; and Not a Detached Proc

          .else                            ; If not Mon Query or request
                                           ; From a Detached Process
             mov  es:[bx].PktStatus, UNKNOWNCMD
          .endif                           ; Gen_Cat Function Tests

       .else                               ; If an Unknown Request Category
          mov  es:[bx].PktStatus, UNKNOWNCMD
       .endif                              ; Mouse Category Support Tests

       ret                                 ; Return to Request_Handler Rtn
IOCTL  ENDP


;************************************************************************
;*
;*  FUNCTION NAME :  DEINS
;*
;*  DESCRIPTION   :  Deinstallation Request handler routine.
;*
;*                   Releases all system resources claimed.  Sets a
;*                   flag disabling support. Runs with Ints disabled.
;*
;*  ENTRY POINT   :  DEINS                       LINKAGE:  CALL NEAR
;*
;*  INPUT         :  ES:BX points to the request block.
;*                   SI has offset to current session control block.
;*
;*  RETURN-NORMAL :  Always, Mouse DD is deinstalled.  Request
;*                   Block Status field return code setup.
;*
;*  RETURN-ERROR  :  N/A
;*
;*  EFFECTS       :  Stack is clean on return.   AX, CX, DX, SI, and DI
;*                   registers are changed.
;*
;*  INTERNAL REFERENCES:
;*     ROUTINES:  NONE.
;*
;*  EXTERNAL REFERENCES:
;*     ROUTINES:  NONE.
;*     DevHlps:   MonitorCreate
;*
;*************************************************************************
;*
;*BeginSub  DEINS
;*
;* WHILE <there are more sessions> DO
;*    IF <current session is not VDM session control>
;*       call Device_Help(MonitorCreate) to destroy the mon chain
;*    ENDIF
;*    set session open handle count to 0
;*    increment current session
;* ENDWHILE
;* set deinstalled flag to shut down all operations
;* return
;*
;*EndSub  DEINS
;*
;***********************************************************************

DEINS  PROC  NEAR
       ASSUME    CS:CSEG2, SS:nothing, ES:nothing, DS:nothing

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

       EnterProc
       mov  TempDS, ds                   ; Save Mouse Data Segment
       mov  TempES, es                   ; Save Request Block
       mov  TempBX, bx                   ; Address

       cli                               ; Hold Interrupts for Deinstallation

       test SynchFlag, APM_IDCACTIVE     ; APM active ?    ; @V2.1XXX02
       .if <nz> AND
       .if <APMIDCHandle ne 0> AND
       .if <ds:APMDD.ProtEntry ne 0>
          mov  APMIDCDereg.DEREG_Function, APMIDC_Deregister
          mov  ax, APMIDCHandle
          mov  APMIDCDereg.DEREG_hClient, ax
          lea  bx, APMIDCDereg
          push ds
          pop  es                        ; es:bx -> APM registration packet
          call ds:APMDD.ProtEntry        ; go do the call
          mov  APMIDCHandle,0            ; clear IDC Handle
          and  SynchFlag, APM_IDCINACTIVE ; Indicate IDC disabled ; @V2.1XXX02
          clc                            ; set good return code

       .endif

       xor  cx, cx                       ; Clear loop counter, SG = 0

       sti                               ; Deinstall complete, Allow interrupts

       mov  fs:DeInstall, ON             ; Flag Mouse as DeInstalled
       mov  es, TempES                   ; Restore Request Block Address
       mov  bx, TempBX

       LeaveProc                         ; Clear local Stack variables

       ret                               ; Return to Request Handler Rtn.
DEINS  ENDP


;************************************************************************
;*
;*  FUNCTION NAME :  INITCOMPLETE        @V2.1XXX01
;*
;*  DESCRIPTION   :  Initialization of all device drivers is now guaranteed
;*                   to be complete.
;*
;*                   Do any initialization where it is required to have
;*                   knowledge that all other device drivers are now loaded
;*                   and their initialization is complete.
;*
;*  ENTRY POINT   :  INITCOMPLETE                LINKAGE:  CALL NEAR
;*
;*  INPUT         :  ES:BX points to the request block.
;*                   SI has offset to current session control block.
;*
;*  RETURN-NORMAL :  Always, this call is only for internal post
;*                   initialization and any error conditions are internal
;*                   to this device driver.
;*
;*  RETURN-ERROR  :  N/A
;*
;*  EFFECTS       :  Stack is clean on return.   AX, CX, DX, SI, and DI
;*                   registers are changed.
;*
;*  INTERNAL REFERENCES:
;*     ROUTINES:  RegisterForAPM
;*
;*  EXTERNAL REFERENCES:
;*     ROUTINES:  NONE.
;*     DevHlps:   NONE
;*
;*************************************************************************
;*
;*BeginSub  INITCOMPLETE
;*
;* call RegisterForAPM
;* return
;*
;*EndSub  INITCOMPLETE
;*
;***********************************************************************

INITCOMPLETE  PROC  NEAR
       ASSUME    CS:CSEG2, SS:nothing, ES:nothing, DS:nothing

       call RegisterForAPM

       ret                       ; Return to Request Handler Rtn.

INITCOMPLETE  ENDP               ; @V2.1XXX01 end

CSEG2    ENDS
         END
