;*DDK*************************************************************************/
;
; COPYRIGHT (C) Microsoft Corporation, 1989
; COPYRIGHT    Copyright (C) 1995 IBM Corporation
;
;    The following IBM OS/2 WARP source code is provided to you solely for
;    the purpose of assisting you in your development of OS/2 WARP device
;    drivers. You may use this code in accordance with the IBM License
;    Agreement provided in the IBM Device Driver Source Kit for OS/2. This
;    Copyright statement may not be removed.;
;*****************************************************************************/

;/*************************************************************************
;*
;* SOURCE FILE NAME = INIT.ASM
;*
;* DESCRIPTIVE NAME = Device Independent init routines
;*
;*
;* VERSION      V2.0
;*
;* DATE         02/29/92
;*
;* DESCRIPTION  Device Independent init routines
;*
;* FUNCTIONS    Mouse_Init        ()
;*              InitFSCB2         ()
;*              FindQSize         ()
;*              FindTypeOverRider ()
;*              FindRelaxed       ()
;*              FindSType         ()
;*              Emi_Init          ()
;*              SkipWhiteSpace    ()
;*              gmDeviceInit      ()
;*              SetupForWait      ()
;*
;* NOTES        This file contains the Mouse Device Driver
;*              initialization code.  It is disposed of after
;*              successful initialization.  This is the last module
;*              in the link list.
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   02/29/92              DCR 509
;*
;*
;**************************************************************************


.386p

.xlist
        include mouse.inc
        include basemaca.inc
        include infoseg.inc
        include emiidc.inc                                          ;emi
        include devclass.inc                                        ;emi
        include singleq.inc                                         ;emi
.list

;*
;*    External Mouse Module Data References
;*


       extrn  Num_Grps          : byte
       extrn  TypeName          : byte
       extrn  STypeName         : byte
       extrn  DDD               : byte
       extrn  DDD2              : byte
       extrn  DeviceData        : byte
       extrn  Mouse$            : byte
       extrn  DfltEQs           : byte
       extrn  SG0               : byte
       extrn  SG1               : byte
       extrn  SG3               : byte
       extrn  TypeOverRider     : byte
       extrn  SType             : byte
       extrn  ABIOS_Mch         : byte
       extrn  Enable_8259       : byte
       extrn  Disable_8259      : byte
       extrn  Enable_28259      : byte
       extrn  Disable_28259     : byte
       extrn  EmiDD             : byte                             ;emi
       extrn  EmiDDName         : byte                             ;emi
       extrn  EmiFlags          : byte                             ;emi
       extrn  EmiMvt            : byte                             ;emi
       extrn  Int_Packet        : byte                             ;emi
       extrn  SInt_Packet       : byte                             ;emi
       extrn  MEvent            : byte                             ;emi
       extrn  DeviceData        : byte                             ;emi
       extrn  Relaxed           : byte
       extrn Init_Time           : byte

       extrn  DDDInit           : word
       extrn  Eq_Length         : word
       extrn  GDT_Seg           : word
       extrn  SMData            : word
       extrn  usQSize           : word
       extrn  PortBase          : word
       extrn  First_Port        : word
       extrn  Dev_LID           : word
       extrn  DevStatus         : word
       extrn  EMaskMax          : word                             ;emi

       extrn  Device_Help       : dword
       extrn  _Device_Help      : dword
       extrn  InfoSegAddr       : dword

       extrn  PDDCMD_MSEEntry   : near
       extrn  DOSSMREGISTERDD   : far

       extrn CheckforPDIDevice   : near
       extrn PDI_Int_Handler     : near
       extrn PDIInit             : near
       extrn SetupCOMForMouse    : near
       extrn ResetSerialMouse    : near

       extrn CheckforMSSDevice   : near
       extrn MSS_Int_Handler     : near
       extrn InitComPort         : near
       extrn MSS_Find_Int        : near

       extrn CheckforINPDevice   : near
       extrn INP_Int_Handler     : near
       extrn InportInit          : near

       extrn CheckforBUSDevice   : near
       extrn BUS_Int_Handler     : near
       extrn BusInit             : near
       extrn EmiEntryPoint       : near                         ;emi

       extrn _RM_MSE_CreateDriver  :far
       extrn _RM_MSE_CreateAdapter :far
       extrn _RM_MSE_CreateDevice  :far
       extrn _RM_MSE_AllocPorts    :far
       extrn _RM_MSE_AllocIRQ      :far
       extrn _RM_MSE_DestroyDriver :far


       public Mouse_Init
       public InitFSCB2
       public FindQSize
       public FindTypeOverRider
       public FindSType
       public SkipWhiteSpace
       public gmDeviceInit
       public SetupForWait
       public IsWaitOver

CSEG     SEGMENT   WORD  PUBLIC  USE16 'CODE'
         ASSUME    CS:CSEG, SS:nothing, ES:nothing, DS:nothing

CSEG2  SEGMENT   WORD  PUBLIC  USE16 'SWAPCODE'
CSEG2  ENDS

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

ENDCODE   EQU   $           ; start of init throw away code


;************************************************************************
;*
;*  FUNCTION NAME :  Mouse_Init
;*
;*  DESCRIPTION   :  Mouse Device Driver H/W Initialization
;*                     Routine.
;*
;*                   This is the main initialization routine.  It
;*                      performs the following steps:
;*                         1.  Gets system variables and sets up msgs.
;*                         2.  Parse the config.sys parameters.
;*                         3.  Issue DevHlp AttachDD on TYPE= parm
;*                             device driver name.
;*                         4.  Initialize session control blocks
;*
;*  NOTES         :  This routine is discarded after initialization.
;*
;*  ENTRY POINT   :  Mouse_Init        LINKAGE:  CALL NEAR
;*
;*  INPUT         :  ES:BX points to the OS/2 Init request block.
;*
;*  RETURN-NORMAL :  Request Block status field set to indicate
;*                   function complete, no error.
;*
;*  RETURN-ERROR  :  Request Block pointer fields set to indicat
;*                   initialization failure.
;*
;*  EFFECTS       :  Stack is clean on return, AX, CX, DX, SI, and DI
;*                   registers are changed.
;*
;*  INTERNAL REFERENCES:
;*     ROUTINES   :  NONE
;*
;*  EXTERNAL REFERENCES:
;*     DevHelps   :  GetDOSVar, AttachDD
;*
;************************************************************************

Mouse_Init  Proc  Far

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

      EnterProc

      mov  TempES, es                    ; Save register values in
      mov  TempBX, bx                    ; Temporary Stack Frame

      mov  es:[bx].PktStatus, 0          ; Clear RB Error Status Flag
;*
;* Save Device Help router entry point.
;*
      mov  di, word ptr es:[bx].InitDevHlp  ; Load DevHlp Entry Pt Offset
      mov  word ptr Device_Help, di         ; Save DevHlp Offset
      mov  word ptr _Device_Help, di        ; Save DevHlp Offset
      mov  di, word ptr es:[bx].InitDevHlp+2; Load DevHlp Entry Pt Selector
      mov  word ptr Device_Help+2, di       ; Save DevHlp Selector
      mov  word ptr _Device_Help+2, di      ; Save DevHlp Selector
;*
;* Use DevHlp (GetDOSVar) to get a pointer to the GDT
;*

      mov  al, GDTINFOINDEX              ; Request GDT InfoSeg value = 1
      mov  dl, DevHlp_GetDOSVar          ; DevHelp function number
      call Device_Help                   ; On Return AX:BX -> to req var

      .if <c>                            ; GetDOSVar failed
         jmp  mi_error
      .endif

      mov  es, ax                        ; Get the GDT level 0 selector and
      mov  ax, word ptr es:[bx]          ; Overwrite the level 3 Selector
      mov  GDT_Seg, ax                   ; Save GDT Selector

      xor  si, si
      mov  es, word ptr GDT_Seg          ; Use the GDT Infoseg selector to
      mov  al, es:[si].SIS_MaxScrnGrp    ; Groups in the system.
      mov  Num_Grps, al                  ; Save # SG's value

;*
;* Use DEVHLP (GetDOSVar) to get LDT InfoSeg
;*
      push  es
      mov   al, LDTINFOINDEX              ; get LDT InfoSeg variable
      mov   dl, DevHlp_GetDOSVar          ; Devhelp function number
      call  Device_Help                   ; Invoke GetDOSVar function
                                          ; AX:BX points to LDT InfoSeg
      mov   es, ax                        ; Get LDT info addr
      les   bx, dword ptr es:[bx]         ; LDT InfoSeg Addr
      mov   word ptr InfoSegAddr,bx
      mov   word ptr InfoSegAddr+2,es
      pop   es
;*
;* Register with the Resource Manager
;*
      inc Init_Time
      pusha
      push es
      mov ax, 1                             ; MOUSESYS
      push ax
      call _RM_MSE_CreateDriver
      pop ax
      pop es
      popa
;*
;* Initialize the extended mouse interface (EMI)                           ;emi
;*                                                                          ;emi

      call Emi_Init                                                       ;emi

      mov  es, TempES                    ; Restore register values from
      mov  bx, TempBX                    ; Temporary Stack Frame

;*
;* Now begin parsing the config.sys line.  Field InitParms points to the
;* 1st character after device= on the line for the MOUSE.SYS dd.
;*

      les  di, es:[bx].InitParms         ; load address to config.sys line
      mov  si, di                        ; save starting point
;*
;* We will first search for the last occasion of the backslash character.
;* This will then point us to MOUSE.SYS and whatever follows. This search
;* was added for            In this            we added support for extended chars
;* in the DEVICE=  line of config.sys. If no backslash chars are encountered
;* our pointer remains at the 1st char after the device= statement.
;*

      .while <<byte ptr es:[di]> ne 0>   ; For all chars on line
         .if <<byte ptr es:[di]> eq '\'> ; If lower case alpha char
            mov  si, di                  ; New starting point
            inc  si
         .endif
         inc di
      .endwhile

      mov  di, si                        ; es:di -> MOUSE.SYS ...
      mov  al, es:[di]
;*
;* Skip over MOUSE.SYS to the 1st non blank character or EOL is reached.
;*

      .while < al ne ' ' > AND           ; Skip everything until a
      .while < al ne ',' > AND           ; Blank, comma, Tab, or EOLN
      .while < al ne TAB > AND           ; Is encountered
      .while < al ne LF > AND
      .while < al ne CR > AND
      .while <al ne 0>
         inc  di                         ; Update line index
         mov  al, es:[di]                ; Get next char
      .endwhile
;*
;* At this point ES:DI points to the first character after MOUSE.SYS and
;* AL holds that character value. We will convert the remaining characters
;* to upper case.
;*

      mov  TempDI, di
      push di
      .while < al ne 0>
         .if <al ge 'a'> AND       ; and if a lower case letter
         .if <al le 'z'>
            add  al, 'A'-'a'       ; convert to upper case
            mov  es:[di], al
         .endif
         inc  di
         mov  al, es:[di]
      .endwhile
      pop  di

      call FindRelaxed

      mov  es, TempES              ; offset to char string
      mov  di, TempDI              ; offset to char string

      call  FindQSize
      .if <c>
         jmp  mi_error
      .endif

      mov  ax, usQSize
      imul ax, ELRec_Size          ; QSize value in AX, use it to
      mov  Eq_Length, ax           ; Calc event que size (Bytes)

      call  FindTypeOverRider
      .if <c>
         jmp  mi_error
      .endif

      .if <TypeOverRider eq TRUE>
         mov  bx, offset TypeName  ; offset to dependent DD name
         mov  di, offset DDD       ; attachDD return structure
         mov  dl, DevHlp_AttachDD  ; function number
         call Device_Help          ; go do the attach
         .if <nc>                  ; if successfull
            or   DDDInit, DI_IDC   ; show IDC init needed
         .else                     ; else we are now attached
            jmp  mi_error
         .endif                    ; end error check on attach
      .else
         call gmDeviceInit
         jc  mi_error
      .endif

      mov  es, TempES                    ; offset to char string
      mov  di, TempDI                    ; offset to char string

      call FindSType

      .if <SType eq TRUE>
         mov  bx, offset STypeName       ; offset to 2nd dependent DD name
         mov  di, offset DDD2            ; attachDD return structure
         mov  dl, DevHlp_AttachDD        ; function number
         call Device_Help                ; go do the attach
         .if <nc>                        ; if successfull
            or   DDDInit, DI_IDC         ; show IDC init needed
         .else                           ; else we are now attached
            jmp  mi_error
         .endif                          ; end error check on attach
      .endif

      lea  si, Mouse$                    ; set ds:si -> mouse$ in data seg
      push CSEG2                         ; 
      pop  es                            ; 
      mov  di, offset PDDCMD_MSEEntry    ; es:di -> 16:16 entry
      mov  dl, DevHlp_RegisterPDD        ; specify function
      call Device_Help                   ; go call function

;*
;*     Now register ourselves with the session manager so that we will be
;*     notified of all screen group switch control.  If that works then
;*     initialize the pre-allocated screen group control blocks (harderror,
;*     shell, and pop-up).  Then set the end of code and data segments so
;*     that both will be shrunk.
;*

      push ds
      push offset SMData
      call DOSSMREGISTERDD

      .if <ZERO ax>
         mov  bx, offset DfltEQs
         lea  si, SG0                    ; offset of SG0
         call InitFSCB2                  ; initialize it
         mov  [si].E_Queue, bx           ; Get pointer to event queue

         lea  si, SG1                    ; offset of SG1
         call InitFSCB2                  ; initialize it
         add  bx, Eq_Length              ; next queue area
         mov  [si].E_Queue, bx           ; store starting offset

         lea  si, SG3                    ; offset of SG3
         call InitFSCB2                  ; initialize it
         add  bx, Eq_Length              ; next queue area
         mov  [si].E_Queue, bx           ; store starting offset
         add  bx, Eq_Length              ; total size of 3 event queues
         mov  dx, bx                     ; size of preallocated event queues
      .else
         jmp  mi_error
      .endif

      mov  es, TempES                    ; restore init packet selector
      mov  bx, TempBX                    ; restore init packet offset

      .if <DeviceData.MouseType eq PDI_DEVICE>
         lea   ax, CheckforMSSDevice     ; 56543
      .elseif <DeviceData.MouseType eq MSS_DEVICE>
         lea   ax, INP_Int_Handler
      .elseif <DeviceData.MouseType eq INP_DEVICE>
         lea   ax, BUS_Int_Handler
      .elseif <DeviceData.MouseType eq BUS_DEVICE>
         lea   ax, CheckforPDIDevice
      .else
         lea   ax, PDI_Int_Handler
      .endif

      mov  word ptr es:[bx].InitEcode, ax   ; set end of code
      mov  ax, dx                           ; add size of 3 event queues
      mov  word ptr es:[bx].InitEdata, ax   ; send end of data
      jmp  mi_exit

mi_error:
      pusha
      call _RM_MSE_DestroyDriver
      popa
      mov  es, TempES                    ; LocalVar = Req Blk Selector
      mov  bx, TempBX                    ; LocalVar = Req Blk Offset
      or   es:[bx].PktStatus, INITBAD    ; Flag Hard Init Err = ABORT
      mov  word ptr es:[bx].InitEcode, 0 ; set end of code
      mov  word ptr es:[bx].InitEdata, 0 ; set end of data

mi_exit:
      mov Init_Time, 0
      LeaveProc
      ret                         ; return to strategy

Mouse_Init  EndP

;************************************************************************
;*
;*  FUNCTION NAME :  InitFSCB2
;*
;*  DESCRIPTION   : Initialize the Full Screen Control Block
;*
;*                  This routine is called to initial the control
;*                  block used for a Full Screen Group.
;*
;*  NOTES         : This routine is an exact duplicate of InitFSCB. By
;*                  adding a copy here we are able to put InitFSCB into
;*                  the swappable code segment. This routine is only used
;*                  at init time therefore it will be discarded with
;*                  the rest of the init code.
;*
;*  INPUT         :  ds:si points to the FSCB to initialize
;*
;*  OUTPUT        : ds:si points to the control block
;*
;*  SIDE EFFECTS  :  stack is clean.
;*
;************************************************************************
;* PSEUDOCODE :
;*
;* BeginSub  InitFSCB2
;*
;*  call DDDD(DisableDevice) to disable the mouse
;*  return
;*
;* EndSub  InitFSCB2
;*
;************************************************************************

InitFSCB2  proc  near


        mov [si].Hdle_Cntr, 0        ; Init handle counter to zero

        mov ax, si                   ; Get offset to start of FS CB
        add ax, SRec_Size            ; End of FS CB is start of event queue
        mov [si].E_Queue, ax         ; Get pointer to event queue

        mov [si].Eq_PID, 0           ; 
        mov [si].D_Status, 0
        mov [si].Chain_Size, 0       ; 
        mov [si].Chain_Hdle, 0       ; 
        mov [si].Screen_Entp, 0      ; 
        mov [si].Screen_Tble, 0      ; 
        mov [si].Screen_DOff, 0      ; 
        mov [si].Screen_DSeg, 0      ; 
        mov [si].MLength, 0          ; 
        mov [si].Ptr_Flags, 0        ; 
        mov [si].Cur_Config, 0       ; 
        mov [si].CfgOffset, 0        ; 
        mov [si].CfgSelector, 0      ; 
        ret

InitFSCB2  endp

;************************************************************************
;*
;*  FUNCTION NAME :  FindQSize
;*
;*  DESCRIPTION   :  Find the QUEUE size specified by the
;*                     caller via the QSIZE= parameter in the
;*                     CONFIG.SYS file.
;*
;*  FUNCTION      :  This routine is called with ES:DI pointing to the
;*                   first character after DEVICE=. It first looks for
;*                   the last occurance of the backslash '\' character
;*                   and resets the pointer to the next character
;*                   which should be the first character of the device
;*                   driver name. It then resets the pointer to the
;*                   first character after the device driver name.
;*                   It changes all lower case letters to uppercase
;*                   letters for less character testing. It then
;*                   looks for the keywords QSIZE, then =, then
;*                   COM. The next character after COM is the port
;*                   number. The number is checked if it is between
;*                   1 and 8. If so, this number is returned to
;*                   the caller in the AX register with the carry
;*                   flag clear.
;*
;*  ENTRY POINT   :  FindQSize         LINKAGE:  CALL NEAR
;*
;*  INPUT         :  ES:DI points to DEVICE=uest block.
;*
;*  RETURN-NORMAL : Carry flag clear
;*                  AX = com port number
;*
;*  RETURN-ERROR  :  Carry flag set
;*
;*  EFFECTS       :  Stack is clean on return, NO registers changed.
;*
;*  INTERNAL REFERENCES:
;*     ROUTINES   :  None
;*
;*  EXTERNAL REFERENCES:
;*     ROUTINES   :  None.
;*
;*  CONTEXT       :
;*                   Init time strategy request.
;*
;************************************************************************


FindQSize  proc  near

       push  es
       push  si
       push  di

       .while < <byte ptr es:[di]> ne 'Q'>
         .if < <byte ptr es:[di]> ne 0 >
            inc  di
         .else
           .if  <bit EmiFlags nz EMI_ACTIVE>           ;emi
              mov  usQSize, DEFAULT_QSIZE              ;emi
           .else                                       ;emi
              mov  usQSize, 10
           .endif                                      ;emi
           clc                                         ;emi
           jmp fqs_exit
         .endif
       .endwhile

       .if < <byte ptr es:[di+1]> ne 'S'> OR
       .if < <byte ptr es:[di+2]> ne 'I'> OR
       .if < <byte ptr es:[di+3]> ne 'Z'> OR
       .if < <byte ptr es:[di+4]> ne 'E'>
          stc
          jmp  fqs_exit
       .endif

       add di, 5
       call  SkipWhiteSpace

       .if < <byte ptr es:[di]> eq '='>
          inc  di
       .else
          stc
          jmp  fqs_exit
       .endif

       call SkipWhiteSpace

        xor     si,si
nxtdig: mov     al,es:[di]
        cmp     al,' '
        je      eodigs
        cmp     al,TAB
        je      eodigs
        cmp     al,0
        je      eodigs
        cmp     al,'0'
        jl      badext
        cmp     al,'9'
        jg      badext
        xor     ah,ah
        sub     al,'0'
        imul    si,10
        add     si,ax
        inc     di
        jmp short nxtdig
eodigs: cmp     si,0
        jle     badext
notmin: cmp     si,100
        jle     goodex
badext: stc
        jmp short fqs_exit
goodex: mov     usQSize,si
        clc
fqs_exit:
        pop     di
        pop     si
        pop     es
        ret

FindQSize  endp

;************************************************************************
;*
;*  FUNCTION NAME :  FindTypeOverRider
;*
;*  DESCRIPTION   :  Find the TYPE= over rider
;*
;*                   This routine is called with ES:DI pointing to the
;*                   first whitespace character after MOUSE.SYS on the
;*                   DEVICE= line in the CONFIG.SYS file. It will
;*                   search for the first occurance of TYPE= and
;*                   grab the device driver name specified. The
;*                   device driver name will be copied to the TypeName
;*                   location which will be used for idc communication.
;*
;*
;*  ENTRY POINT   :  FindTypeOverRider       LINKAGE:  CALL NEAR
;*
;*  INPUT         :  ES:DI points to the first character after MOUSE.SYS
;*                   on the DEVICE= line in the CONFIG.SYS file.
;*
;*                    TypeOverRider has been initialized to TRUE
;*
;*
;*  RETURN-NORMAL : Carry flag clear
;*                          TypeName updated
;*                          TypeOverRider = TRUE if found
;*                                        = FALSE not found
;*
;*                          ES:DI points to the first whitespace character
;*                                after the device name just found.
;*
;*  RETURN-ERROR  :  Carry flag set
;*
;*  EXIT-NOTE     : The TypeOverRider will be set to FALSE if
;*
;*  EFFECTS       :  Stack is clean on return, NO registers changed.
;*
;*  INTERNAL REFERENCES:
;*     ROUTINES   :  None
;*
;*  EXTERNAL REFERENCES:
;*     ROUTINES   :  None.
;*
;*  CONTEXT:
;*           Init time strategy request.
;*
;************************************************************************

FindTypeOverRider  proc  near

       push es
       push di
;*                                                                        ;emi
;* the following code fixes a     in the GA code that wouldn't allow      ;emi
;* QSIZE and TYPE parms                                                   ;emi
;*                                                                        ;emi

       .repeat                                                            ;emi
          mov  al, byte ptr es:[di]                                       ;emi
          .while <al ne 'T'>                                              ;emi
            .if <zero al>              ; At EOL                           ;emi
               mov TypeOverRider,FALSE ; default is TRUE                  ;emi
               clc                     ; indicate NONE found              ;emi
               jmp fto_exit                                               ;emi
             .endif                                                       ;emi
             inc di                                                       ;emi
             mov  al, byte ptr es:[di]                                    ;emi
          .endwhile                                                       ;emi

          inc di                                                          ;emi

          .if < <byte ptr es:[di-2]> ne 'S'> AND  ; Might be "STYPE"      ;emi
          .if < <byte ptr es:[di+0]> eq 'Y'> AND                          ;emi
          .if < <byte ptr es:[di+1]> eq 'P'> AND                          ;emi
          .if < <byte ptr es:[di+2]> eq 'E'>                              ;emi
             add di, 3                                                    ;emi
             call  SkipWhiteSpace                                         ;emi
             .leave <<byte ptr es:[di]> eq '='>   ; Leave when '=' found  ;emi
          .endif                                                          ;emi
       .until                                                             ;emi

       inc  di                                    ; skip the '=' sign     ;emi

       call SkipWhiteSpace

       lea  si, TypeName
       mov  al, es:[di]

       .while < al ne 0>   AND          ; save DD Device Driver entry point
       .while < al ne ' '> AND
       .while < al ne TAB>
          mov  [si], al
          inc  si
          inc  di
          mov  al, es:[di]
       .endwhile

fto_exit:
       pop  di
       pop  es
       ret

FindTypeOverRider  endp

;************************************************************************
;*
;*  FUNCTION NAME :  FindRelaxed
;*
;*  DESCRIPTION   :  Find the RELAXED keyword
;*
;*                   This routine is called with ES:DI pointing to the
;*                   first whitespace character after MOUSE.SYS on the
;*                   DEVICE= line in the CONFIG.SYS file. It will
;*                   search for the first occurance of RELAXED
;*
;*  ENTRY POINT   :  FindRelaxed             LINKAGE:  CALL NEAR
;*
;*  INPUT         :  ES:DI points to the first character after MOUSE.SYS
;*                   on the DEVICE= line in the CONFIG.SYS file.
;*
;*
;*  RETURN-NORMAL : Carry flag clear
;*
;*                    ES:DI points to the first whitespace character
;*                     after the device name just found.
;*
;*  RETURN-ERROR  :  Carry flag set
;*
;*  EFFECTS       :  Stack is clean on return, NO registers changed.
;*
;*  INTERNAL REFERENCES:
;*     ROUTINES   :  None
;*
;*  EXTERNAL REFERENCES:
;*     ROUTINES   :  None.
;*
;*  CONTEXT       :
;*           Init time strategy request.
;*
;************************************************************************

FindRelaxed        proc  near

       push es
       push di

       .repeat
          mov  al, byte ptr es:[di]
          .while <al ne 'R'>
            .if <zero al>              ; At EOL
               clc                     ; indicate not found
               jmp fr_exit
             .endif
             inc di
             mov  al, byte ptr es:[di]
          .endwhile

          inc di

          .if < <byte ptr es:[di+0]> eq 'E'> AND
          .if < <byte ptr es:[di+1]> eq 'L'> AND
          .if < <byte ptr es:[di+2]> eq 'A'> AND
          .if < <byte ptr es:[di+3]> eq 'X'> AND
          .if < <byte ptr es:[di+4]> eq 'E'> AND
          .if < <byte ptr es:[di+5]> eq 'D'>
                mov     Relaxed,1     ; relax our sync checking
          .endif
       .until

fr_exit:
       pop  di
       pop  es
       ret

FindRelaxed        endp


;************************************************************************
;*
;*  FUNCTION NAME :  FindSType
;*
;*  DESCRIPTION   :  Check to see if the STYPE= parameter
;*                     has been specified on the DEVICE=
;*                     line in the CONFIG.SYS file.
;*
;*  FUNCTION      :  This routine is called with ES:DI pointing to the
;*                    first whitespace character after MOUSE.SYS on the
;*                    DEVICE= line in the CONFIG.SYS file.
;*
;*  ENTRY POINT   :  FindSType               LINKAGE:  CALL NEAR
;*
;*  INPUT         :  ES:DI points to the first character after MOUSE.SYS
;*                     on the DEVICE= line in the CONFIG.SYS file.
;*
;*                      SType has been initialized to FALSE
;*
;*
;*  RETURN-NORMAL : SType = TRUE if found
;*                     = FALSE not found
;*
;*  RETURN-ERROR  :  Carry flag set
;*
;*  EFFECTS:
;*
;*  INTERNAL REFERENCES:
;*     ROUTINES   :  None
;*
;*  EXTERNAL REFERENCES:
;*     ROUTINES   :  None.
;*
;*  CONTEXT       :
;*                    Init time strategy request.
;*
;************************************************************************


FindSType  proc  near
;*
;* the following code fixes a     in the GA code that wouldn't allow     ;emi
;* QSIZE and STYPE parms                                                 ;emi
;*                                                                       ;emi

       .repeat                                                            ;emi
          mov  al, byte ptr es:[di]                                       ;emi
          .while <al ne 'S'>                                              ;emi
            .if <zero al>                                                 ;emi
               clc                                                        ;emi
               jmp fst_exit                                               ;emi
             .endif                                                       ;emi
             inc di                                                       ;emi
             mov  al, byte ptr es:[di]                                    ;emi
          .endwhile                                                       ;emi
          inc di                                                          ;emi
          .if < <byte ptr es:[di+0]> eq 'T'> AND                          ;emi
          .if < <byte ptr es:[di+1]> eq 'Y'> AND                          ;emi
          .if < <byte ptr es:[di+2]> eq 'P'> AND                          ;emi
          .if < <byte ptr es:[di+3]> eq 'E'>                              ;emi
             add di, 4                                                    ;emi
             call  SkipWhiteSpace                                         ;emi
             .leave <<byte ptr es:[di]> eq '='>                           ;emi
          .endif                                                          ;emi
       .until                                                             ;emi
       inc  di    ; skip the = sign                                       ;emi

       call SkipWhiteSpace

       lea  si, STypeName
       mov  al, es:[di]

       .while < al ne 0>   AND
       .while < al ne ' '> AND
       .while < al ne TAB>
          mov  [si], al
          inc  si
          inc  di
          mov  al, es:[di]
          mov  SType, TRUE
       .endwhile

fst_exit:
       ret

FindSType  endp

;********************************************************************
;*
;*  FUNCTION NAME :  Emi_Init
;*
;*  DESCRIPTION   :  Initialize EMI
;*
;*  FUNCTION      :  Make connection with the emi driver. Check to see
;*                   if the aux port is being used by the emi driver.
;*
;*                   This is here instead of in EMI.ASM so it will
;*                   get freed after initialization.
;*
;*  ENTRY POINT   :  Emi_Init           LINKAGE:  CALL NEAR
;*
;*  INPUT         :  none
;*                   DS - MOUSE$ data selector
;*
;*  RETURN-NORMAL : OK
;*
;*  RETURN-ERROR  :  Never.
;*
;*  EFFECTS       :  Set global switch indicating if emi is active and
;*                   whether the Aux port is being used.
;*
;*  INTERNAL REFERENCES:
;*     ROUTINES   :  NONE
;*
;*
;*  EXTERNAL REFERENCES:
;*     ROUTINES   :  NONE
;*     DevHelps   :  AttachDD
;*
;************************************************************************


                                                                        ;emi
Emi_Init proc  near                                                     ;emi
;*                                                                      ;emi
;* attach to the emi driver                                             ;emi
;*                                                                      ;emi

  mov  bx, offset EmiDDName        ; driver name                        ;emi
  mov  di, offset EmiDD            ; attachDD return structure          ;emi
  mov  dl, DevHlp_AttachDD         ; function number                    ;emi
  call Device_Help                 ; go do the attach                   ;emi
  .if  nc                          ; if successfull                     ;emi
     or   EmiFlags,EMI_ACTIVE+EMI_NEED_CONFIG ;present and needs config ;emi
;*                                                                      ;emi
;* see if emi will be using the aux port by searching the device table  ;emi
;* for emi devices that request use of the aux port                     ;emi
;*                                                                      ;emi

     mov  al, DHGETDOSV_DEVICECLASSTABLE                                ;emi
     mov  cx, DEVCLASS_INPUT    ; input class                           ;emi
     mov  dl, DevHlp_GetDOSVar  ; function number                       ;emi
     call Device_Help                                                   ;emi
     .if  nc                                                            ;emi
        mov  es, ax                                                     ;emi
        mov  cx, es:[bx].DCCount                                        ;emi
        .if  <nonzero cx>                                               ;emi
           add  bx,DCTableEntries-DCCount                               ;emi
           .repeat                                                      ;emi
              .if  <bit es:[bx].DCFlags nz REG_EXT_IF> AND              ;emi
              .if  <bit es:[bx].DCFlags nz REG_AUX>                     ;emi
                 or   EmiFlags,EMI_AUX_BUSY ;aux port to be used by emi ;emi
              .endif                                                    ;emi
           .loop                                                        ;emi
        .endif                                                          ;emi
     .endif                                                             ;emi

;*                                                                      ;emi
;* fill in the Mouse Variable Table                                     ;emi
;*                                                                      ;emi

     lea si, EmiMvt                                                     ;emi
                                                                        ;emi
     lea ax, EmiEntryPoint                ; IDC entry point             ;emi
     mov word ptr EmiMvt.EmiEntry,ax                                    ;emi
     mov ax, cs                                                         ;emi
     and ax, 0fff8h                                                     ;emi
     mov word ptr EmiMvt.EmiEntry+2,ax                                  ;emi
                                                                        ;emi
     lea ax,Int_Packet                    ; Interrupt packets           ;emi
     mov word ptr EmiMvt.IntPacket,  ax                                 ;emi
     mov word ptr EmiMvt.IntPacket+2,ds                                 ;emi
     lea ax,SInt_Packet                                                 ;emi
     mov word ptr EmiMvt.SIntPacket,  ax                                ;emi
     mov word ptr EmiMvt.SIntPacket+2,ds                                ;emi
                                                                        ;emi
     lea ax,MEvent.Mon_Time               ; Where to pass time stamp    ;emi
     mov word ptr EmiMvt.TimeStamp,  ax                                 ;emi
     mov word ptr EmiMvt.TimeStamp+2,ds                                 ;emi
                                                                        ;emi
     lea ax,DeviceData                    ; Where to find DeviceData    ;emi
     mov word ptr EmiMvt.SDevData,ax                                    ;emi
     mov word ptr EmiMvt.SDevData+2,ds                                  ;emi
                                                                        ;emi
     lea ax,EMaskMax                      ; Where to find Event Mask    ;emi
     mov word ptr EmiMvt.EventMask,ax                                   ;emi
     mov word ptr EmiMvt.EventMask+2,ds                                 ;emi
                                                                        ;emi
  .endif                                                                ;emi
  ret                                                                   ;emi
Emi_Init  Endp                                                          ;emi

;************************************************************************
;*
;*  FUNCTION NAME :  SkipWhiteSpace
;*
;*  DESCRIPTION   :  This routine will skip over all tabs and
;*                     blank spaces.
;*
;*  FUNCTION      :  This routine is called with ES:DI pointing a
;*                   character string. The pointer will be incremented
;*                   to point to the first non-whitespace character
;*
;*  ENTRY POINT   :  SkipWhiteSpace    LINKAGE:  CALL NEAR
;*
;*  INPUT         :  ES:DI points to the character string.
;*
;*  RETURN-NORMAL : Always
;*                    ES:DI - will point to the first non-whitespace
;*                       character encountered.
;*
;*  RETURN-ERROR  :  None
;*
;*
;*  INTERNAL REFERENCES:
;*     ROUTINES   :  None
;*
;*  EXTERNAL REFERENCES:
;*     ROUTINES   :  None.
;*
;*  CONTEXT       :
;*                    Init time strategy request.
;*
;************************************************************************


SkipWhiteSpace  proc  near

        .while < <byte ptr es:[di]> eq ' '> OR
        .while < <byte ptr es:[di]> eq TAB >
           inc  di
        .endwhile
        ret

SkipWhiteSpace  endp

;*********************************************************************
;*
;*  FUNCTION NAME :  gmDeviceInit
;*
;*  DESCRIPTION   :  Generic Pointing Device Support Init
;*
;*  FUNCTION      :  This routine initializes the hardware dependent
;*                   device driver.
;*
;*  ENTRY POINT   :  gmDeviceInit      LINKAGE:  CALL NEAR
;*
;*  INPUT         :  ES:BX points to the request block.
;*
;*  RETURN-NORMAL :  Device is initialized.
;*
;*  RETURN-ERROR  :  Device left disabled.
;*
;*  EFFECTS       :  Stack is clean on return, NO registers changed.
;*
;*  INTERNAL REFERENCES:
;*     ROUTINES   :  None
;*
;*  EXTERNAL REFERENCES:
;*     ROUTINES   :  NONE
;*
;*********************************************************************


gmDeviceInit  Proc  Near

;*
;* Now check to make sure we are loading on an ABIOS machine.
;*

       mov  al, 0bh                      ; APD Device ID
       mov  bl, 1                        ; Get 1st LID
       xor  dh, dh                       ; reserved, must be 0
       mov  dl, DevHlp_GetLIDEntry       ; ABIOS function
       call Device_Help                  ; invoke Dev Help

       .if <nc>                          ; If this is an ABIOS machine
           mov  ABIOS_Mch, TRUE          ; ABIOS_Mch initially set to FALSE
           mov  dl, DevHlp_FreeLIDEntry
           call Device_Help              ; give LID back for now
       .elseif < ax ne Error_ABIOS_Not_Present >
           mov  ABIOS_Mch, TRUE
       .endif
;;*
;;* 84853 - Move this code down below so it checks for serial mouse first.
;;*
;;*       .if <bit EmiFlags z  EMI_AUX_BUSY>                             ;emi
;;*          call  CheckforPDIDevice
;;*          .if  <nc>
;;*             mov  DeviceData.MouseType, PDI_DEVICE
;;*             mov  DeviceData.IRQ, 12
;;*             mov  ax, offset PDI_Int_Handler
;;*             jmp  jc1
;;*          .endif
;;*       .endif                                                         ;emi

       call  CheckforMSSDevice
       .if  <nc>
          mov  DeviceData.MouseType, MSS_DEVICE
          mov  bx, PortBase
          mov  DeviceData.ComPort, bx
;* AGGGH!  and  bx, 0f00h
;*         inc  bh
;*  THIS   mov  DeviceData.IRQ, bh
;*   IS
;*  VERY   mov  cl, bh
;* COM1-4  mov  ax, 0001h             ; Build 8259 IC Mask
;* SPEC-   shl  ax, cl                ; from returned IRQ #
;*  IFIC

          call MSS_Find_Int           ; find selected interrupt level
          jnc  havint

          mov  bx, PortBase           ; couldn't autodetect... hardwire it
          and  bx, 0f00h
          inc  bh
          mov  DeviceData.IRQ, bh

          mov  cl, bh
          mov  ax, 0001h              ; Build 8259 IC Mask
          shl  ax, cl                 ; from returned IRQ #

havint:   mov  DeviceData.IRQ,bh
          mov  Disable_8259, al       ; Save Disable 8259 Mask
          mov  Disable_28259, ah      ; Save Disable 2nd 8259 Mask
          not  ax                     ; Invert Mask for Enable Bits
          mov  Enable_8259, al        ; Save Enable 8259 Mask
          mov  Enable_28259, ah       ; Save Enable 2nd 8259 Mask

          mov  dx,PortBase            ;DEBUG
          mov  cx,LONGDELAY           ;DEBUG
          call SetupCOMForMouse       ;DEBUG
          call ResetSerialMouse       ;DEBUG

          mov  ax, offset MSS_Int_Handler
          jmp  jc1
       .endif
;;*
;;* 84853  This was moved here from above.
;;*
       .if <bit EmiFlags z  EMI_AUX_BUSY>                             ;emi
          call  CheckforPDIDevice
          .if  <nc>
             mov  DeviceData.MouseType, PDI_DEVICE
             mov  DeviceData.IRQ, 12
             mov  ax, offset PDI_Int_Handler
             jmp  jc1
          .endif
       .endif                                                         ;emi

       .if <ABIOS_Mch eq FALSE>
          call CheckforINPDevice
          .if <nc>
             mov  DeviceData.MouseType, INP_DEVICE
             mov  DeviceData.IRQ, al
             mov  ax, offset INP_Int_Handler
             jmp  jc1
          .endif

          call CheckforBUSDevice
          .if <nc>
             mov  First_Port, BUS_First_Possible
             mov  DeviceData.MouseType, BUS_DEVICE
             mov  DeviceData.IRQ, al
             mov  ax, offset BUS_Int_Handler
             jmp  jc1
          .endif

       .endif
;*
;* If we reach this point we haven't found any pointing devices. We must
;* still load because the install program has to be able to call the ioctl
;* GetPointerDeviceID.
;*

       clc                                ; nothing found
       jmp  jc2

;*
;* Now go claim the IRQ level.
;*

jc1:
       xor bh, bh
       mov bl, DeviceData.IRQ              ; get IRQ needed

       pusha
       push es
       push bx
       call _RM_MSE_AllocIRQ
       or ax, ax
       pop bx
       pop es
       popa
       jne  short IRQTaken

       mov  dh, 01h                        ; share the level
       mov  dl, DevHlp_SetIRQ              ; function number
       call Device_Help                    ; go do it

       .if <c>                             ; if error
          xor  dh, dh                      ; IRQ level as unshared
          call Device_Help                 ; try again
          .if <c>                          ; if error
             jmp  jc2
          .endif
       .endif
IRQTaken:

      .if <DeviceData.MouseType eq PDI_DEVICE>
         call  PDIInit
      .elseif <DeviceData.MouseType eq MSS_DEVICE>
         call  InitComPort
      .elseif <DeviceData.MouseType eq INP_DEVICE>
         call  InportInit
      .elseif <DeviceData.MouseType eq BUS_DEVICE>
         call  BusInit
      .endif

      or   DevStatus, gREADENABLE         ; We are now ready for events

      pusha
      push es
      mov al, DeviceData.MouseType
      xor ah, ah
      push ax
      call _RM_MSE_CreateAdapter
      pop ax
      call _RM_MSE_CreateDevice
      pop  es
      popa

jc2:
       ret
gmDeviceInit  endp


;******************************************************************************
;*
;* FUNCTION NAME   : SetupForWait
;*
;* DESCRIPTION     : This procedure accepts the number of milliseconds that we
;*                   we will want to delay for and will set things up for wait.
;*
;* ENTRY           : CX            Number of milliseconds to delay for
;*                   GDT_Seg       Gives bimodal address of System Info Seg
;*
;* EXIT            : BX:CX         Dword value giving ending time
;*                   ES:DI         Points at dword in SIS giving current time
;*                   Interrupts enabled
;*
;*                   ALTERS  BX, CX, DI, ES
;******************************************************************************

SetupForWait  proc  near

        xor     bx,bx                 ; BX:CX give # msecs to delay.
        mov     es, GDT_Seg           ; ES address SIS.
        mov     di, SIS_MsCount       ; ES:DI points at msec counter.

        cli                           ; Interrupts off while accessing time.
        add     cx,word ptr es:[di]   ; Determine ending time by adding the
        adc     bx,word ptr es:[di+2] ;  amount of the delay to the time.
        sti                           ; Make sure interrupts are enabled!

        ret

SetupForWait  endp

;*****************************************************************************
;*
;* FUNCTION NAME: IsWaitOver
;*
;* DESCRIPTION  : This procedure accepts the current time and the ending time
;*                and retruns an indication of whether the current time is past
;*                the ending time.
;* ENTRY        :
;*                   BX:CX        Ending time value (double word)
;*                   ES:DI        Points at current time (double word)
;* EXIT         :
;*                   Carry clear  Current time is not past ending time
;*                   Carry set    Current time is past ending time
;*
;*                   ALTERS  none
;******************************************************************************


IsWaitOver  proc  near

        cli                             ; No interrupts (time may change).
        cmp     bx,word ptr es:[di+2]   ; Compare high words first.
                                        ; Current time exceeds ending time,
                                        ;  leave with carry set.
        jne     short iwo_leave         ; Current time does not exceed ending
                                        ;  time, leave with carry clear.
        cmp     cx,word ptr es:[di]     ; High words are equal. Return with
                                        ;  result of comparison of low words.

iwo_leave:                              ; Carry set or clear appropriately.
        sti                             ; Interrupts ok again.
        ret

IsWaitOver  endp

CSEG     ENDS
         END
