
;/*************************************************************************
;*
;* SOURCE FILE NAME = INIT.ASM
;*
;* DESCRIPTIVE NAME = Initialization routines.
;*
;* 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         02/29/92
;*
;* DESCRIPTION  This file contains the initialization routines
;*
;* FUNCTIONS    Device_Init      Begin mouse device initilization.
;*
;*              FindComNumber    Find which COM port number the was
;*                               specified in the DEVICE= line of the
;*                               CONFIG.SYS file.
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   00/00/00  @V2.0XXX01  DCR 509
;**************************************************************************


.xlist
       include devsym.inc
       include devhlp.inc
       include struc.inc
       include dddd.inc
.list

.286p

;*
;*    External Mouse Module Data References
;*

       extrn Disable_8259        : byte
       extrn Enable_8259         : byte
       extrn DeviceData          : byte
       extrn MseDD               : byte
       extrn MEvent              : byte

       extrn First_Port          : word
       extrn ByteCount           : word
       extrn pComAddr            : word
       extrn DevStatus           : word
       extrn IntPacketOff        : word

       extrn Device_Help         : dword
       extrn _Device_Help        : dword

       extrn ENDDATA             : near
       extrn Interrupt_Handler   : near
       extrn Enable_Device       : near
       extrn Disable_Device      : near

       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


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

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

       public  Device_Init
       public  FindComNumber

;***********************************************************************
;*
;*  FUNCTION NAME :  Device_Init
;*
;*  DESCRIPTION   :  Begin mouse device initilization.
;*
;*                   This routine initializes the hardware dependent
;*                   device driver.
;*
;*  ENTRY POINT   :  Device_Init       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:  DosGetMessage, DosPutMessage
;*
;************************************************************************


Device_Init  Proc  Near

TempES     equ   <(word ptr [bp-2])>
TempBX     equ   <(word ptr [bp-4])>
TempDS     equ   <(word ptr [bp-6])>
status     equ   <(word ptr [bp-8])>
Dev_LID    equ   <(word ptr [bp-10])>

       Enter 10,0

       mov  TempES, es
       mov  TempBX, bx
       mov  status, 0

;*
;*  Equates to be used in this routine
;*

ERR         equ        0001h
LID_DONE    equ        0002h
IRQSET      equ        0004h


;*
;* Get the address to the DevHelp router and save in our DS.
;*

       mov  cx, word ptr es:[bx].InitDevHlp
       mov  word ptr Device_Help, cx
       mov  word ptr _Device_Help, cx
       mov  cx, word ptr es:[bx].InitDevHlp+2
       mov  word ptr Device_Help+2, cx
       mov  word ptr _Device_Help+2, cx
       mov  es:[bx].PktStatus, 00h    ; clear req block status field

       les  di, es:[bx].InitpBPB      ; Point to first character after DEVICE=
       call FindComNumber             ; Updates ComPortNum number
       .if <c>
          or   status, ERR
          jmp  Init_End
       .endif

       pusha
       push es
       mov ax, 2                      ; PCLOGICSYS
       push ax
       call _RM_MSE_CreateDriver
       pop ax
       pop es
       popa

       mov  al, 06h                   ; Async Device ID
       mov  bl, DeviceData.ComPortNum ; Get 1st LID
       xor  dh, dh                    ; reserved, must be 0
       mov  dl, DevHlp_GetLIDEntry    ; ABIOS function
       call Device_Help               ; invoke Dev Help
       .if <nc>
          mov  Dev_LID, ax
          or  status, LID_DONE
       .endif

       mov  al, DeviceData.ComPortNum
       xor  ah, ah
       dec  al
       shl  al, 1
       mov  pComAddr, ax              ; Hooked com off = 2*(Com_Num-1)

       mov  ax, CRT_Data_Seg          ; Get ROM BIOS Data Seg
       mov  es, ax                    ; Loaded into ES Reg
       xor  di, di                    ; Load Base Data Area Offset

       mov  cx, pComAddr              ; Get COMx 40:Offset value

       add  di, cx                    ; Add Bios Base & COMx Offset
       mov  dx, es:[di]               ; Get COMx Base Port Address

       .if <dx eq 0>                  ; if com port does not exist
          or   status, ERR            ; then set error code
          jmp  Init_End               ; and get out now
       .endif

       pusha
       push es
       push dx
       call _RM_MSE_AllocPorts
       or ax, ax
       pop dx
       pop es
       popa
       jnz  ResourceFailed

       mov  First_Port, dx         ; Get first port
       mov  DeviceData.ComPort, dx ; Needed by VMSE

       mov  cl, dh                 ; Use Addr High byte to
       and  cl, 0fh                ; Mask off unwanted bits
       inc  cl                     ; Calc the Port IRQ Level
       mov  DeviceData.IRQ, cl     ; Save Port IRQ Level

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

       mov  Disable_8259, al       ; Save Disable 8259 Mask
       not  al                     ; Invert Mask for Enable Bits
       mov  Enable_8259, al        ; Save Enable 8259 Mask

;*
;* Check to see if port exists.
;*

       mov  al, IIRMASK            ; Load Int ID Reg Mask
       mov  dx, First_Port         ; Get Base Port address 2/3f8h
       add  dx, IIR                ; Get Int ID Register
       in   al, dx                 ; Read Int ID Register

       test al, IIRMASK            ; Check reg permanent bits
       .if <nz>                    ; if port does not exist
          or   status, ERR         ; set error and
          jmp  Init_End            ; get out now
       .endif

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

       mov  ax, offset Interrupt_Handler   ; offset of interrupt routine
       xor  bh, bh                         ; clear upper byte
       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 ResourceFailed
       mov  dh, 01h                        ; share the interrupt 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
ResourceFailed:
               or   status, ERR            ; set error code
               jmp  Init_End               ; and get out
            .endif
       .endif

       or   status, IRQSET                 ; show that IRQ was set
       call Disable_Device                 ; go disable the IRQ

       Setup_Async                         ; Setup Async Controls

;*
;* We have now finished starting all request blocks.  Check and see if there
;* was an error so far.  If so then abort the load, otherwise continue.
;*

Init_End:

       test status, ERR                     ; see if there was an error
       .if <nz>  NEAR                       ; if there was then undo stuff
          test status, IRQSET               ; see if IRQ was done
          .if <nz>                          ; if yes the go release if
             xor  bh, bh                    ; clear upper byte
             mov  bl, DeviceData.IRQ        ; get claimed IRQ level
             mov  dl, DevHlp_UnSetIRQ       ; specify function
             call Device_Help               ; go do it
          .endif

          test status, LID_DONE             ; see if GetLID was done
          .if <nz>                          ; if so then return it
             mov  ax, Dev_LID               ; get LID for call
             mov  dl, DevHlp_FreeLIDEntry
             call Device_Help
          .endif

          BADINIT                   ; now put return status in Req packet

          mov  byte ptr es:[bx].InitcUnit, 0     ; get rid of everything
          mov  word ptr es:[bx].InitpEnd, 0
          mov  word ptr es:[bx].InitpEnd+2, 0

          pusha
          push es
          call _RM_MSE_DestroyDriver
          pop es
          popa

       .else  NEAR                  ; there was no error detected

;*
;* Zero our BIOS area so that no one else can get it.
;*

          mov  ax, CRT_Data_Seg        ; Get ROM BIOS Data Seg
          mov  es, ax                  ; Loaded into ES Reg
          mov  di, pComAddr            ; Get COMx 40:Offset value
          mov  word ptr es:[di], 0     ; Remove Port From ROM BIOS

          pusha
          mov al, 2                    ; MSS_DEVICE - Serial Device
          xor ah, ah
          push ax
          call _RM_MSE_CreateAdapter
          pop ax
          call _RM_MSE_CreateDevice
          popa
;*
;* set end of code and data segments.
;*

          mov  es, TempES
          mov  bx, TempBX
          mov  byte ptr es:[bx].InitcUnit, 0
          mov  word ptr es:[bx].InitpEnd, offset Device_Init
          lea  ax, ENDDATA
          mov  word ptr es:[bx].InitpEnd+2, ax

          call Enable_Device           ; enable the IRQ level

       .endif

       mov  bx, TempBX
       mov  ax, status
       Leave
       ret
Device_Init  EndP

;********************************************************************
;*
;*  FUNCTION NAME :  FindComNumber
;*
;*  DESCRIPTION   :  Find which COM port number the was
;*                     specified in the DEVICE= line of the
;*                     CONFIG.SYS file.
;*
;*                  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 SERIAL, 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   :  FindComNumber     LINKAGE:  CALL NEAR
;*
;*  INPUT         :  ES:DI points to the first character after the
;*                   '=' character in the DEVICE= line.
;*
;*  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.
;*
;************************************************************************


FindComNumber  proc  near


;* ES:DI points to the 1st character after DEVICE=. We will search for the
;* last occasion of the backslash '\' character. This will then point us to
;* XXXXX.SYS and whatever follows. This search was added for @V2.0XXX01 This
;* DCR added support for extended chars in the DEVICE=  line of config.sys.
;* If no backslash chars are encountered our pointer will be reset to the
;* first character after DEVICE=.

       mov  si, di                          ; save starting point
       .while <<byte ptr es:[di]> ne 0>     ; For all chars in line
          .if <<byte ptr es:[di]> eq '\'>   ; If we find a backslash
             mov  si, di                    ; Save this new position
             inc  si                        ; Point to first char after '\'
          .endif
          inc di                            ; Next char
       .endwhile
       mov  di, si                          ; Start of device driver filename.

;*
;* At this point ES:DI points to the device driver name (XXXXX.SYS) and
;* whatever follows. We will skip over XXXXX.SYS to the 1st non blank
;* character. If nothing is after the device name we simply return and use
;* the default com port number which is 1.
;*

       .while <<byte ptr es:[di]> ne ' ' > AND    ; Skip everything until a
       .while <<byte ptr es:[di]> ne TAB >        ; Is encountered
          .if <<byte ptr es:[di]> ne 0 >
             inc  di                              ; Update line index
          .else
             jmp fcn_exit
          .endif
       .endwhile

;*
;* ES:DI points to first character after XXXXX.SYS. We will now convert
;* all lower case characters to upper case characters.
;*

       push di
       .while <<byte ptr es:[di]> ne 0 >
          .if <<byte ptr es:[di]> ge 'a'> AND
          .if <<byte ptr es:[di]> le 'z'>
             add  byte ptr es:[di], 'A'-'a'
          .endif
          inc  di
       .endwhile
       pop  di

       .while <<byte ptr es:[di]> ne 0 > NEAR

          .if <<byte ptr es:[di]> ne 'S' >
             inc  di

          .else NEAR

             .if <<byte ptr es:[di+1]> eq 'E' > AND NEAR
             .if <<byte ptr es:[di+2]> eq 'R' > AND NEAR
             .if <<byte ptr es:[di+3]> eq 'I' > AND NEAR
             .if <<byte ptr es:[di+4]> eq 'A' > AND NEAR
             .if <<byte ptr es:[di+5]> eq 'L' >     NEAR

                add di, 6

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

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

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

                .if <<byte ptr es:[di]> eq 'C' > AND
                .if <<byte ptr es:[di+1]> eq 'O' > AND
                .if <<byte ptr es:[di+2]> eq 'M' >

                   .if <<byte ptr es:[di+3]> ge '1' > AND
                   .if <<byte ptr es:[di+3]> le '4' > AND
                   .if <<byte ptr es:[di+4]> eq ' ' > OR
                   .if <<byte ptr es:[di+4]> eq TAB > OR
                   .if <<byte ptr es:[di+4]> eq 0>

                     mov  al, byte ptr es:[di+3]
                     sub  al, '0'
                     mov  DeviceData.ComPortNum, al
                     clc
                     jmp  fcn_exit
                   .else
                     stc
                     jmp  fcn_exit
                   .endif

                .else
                  stc
                  jmp  fcn_exit
                .endif

             .else
                stc
                jmp fcn_exit
             .endif

          .endif

       .endwhile

fcn_exit:
       ret

FindComNumber  endp

CSEG     ENDS
         END
