;/*************************************************************************
;*
;* SOURCE FILE NAME = MOVE.ASM
;*
;* DESCRIPTIVE NAME = Mouse device independent movement control
;*                    and event reporting 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         03/11/92
;*
;* DESCRIPTION  Mouse device independent movement control
;*              and event reporting routines
;*
;* FUNCTIONS    CalcPixelMvmnt    - Calculate Pixel Movement
;*              CalcProtThreshold - Calculate Thresold in Protect Mode
;*              CalcPtrPos        - Calculate Pointer Position
;*              ReportProtectEvent- Report Protect Mode Mouse Event
;*              PDI_Int_Handler   - Mouse Device Interrupt Handler
;*              MSS_Int_Handler   - Mouse Device Interrupt Handler
;*              Disable_Device    - Disable the Mouse IRQ level
;*              Enable_Device     - Enable the Mouse IRQ level
;*              INP_Int_Handler   - Mouse Device Interrupt Handler
;*              BUS_Int_Handler   - Mouse Device Interrupt Handler
;*
;* NOTES        This file contains the mouse device independent
;*              movement control support and event reporting rtns.
;*
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES    SingleQ DD, QueueWrite
;*                        MonWrite.
;*
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   00/00/00  @V2.0XXX01  53248  DEFECT
;*   00/00/00  @V2.0XXX02  56543  DEFECT
;*   04/04/93  @V2.1XXX03  53232  Add support for Logitech middle button
;*   04/21/93  @V2.1XXX04  67424  Loose mouse when coming back from suspend
;*                                mode on Dell 325nc laptop.
;*   08/16/93  @V2.1RAR01         Rewrite MSS_Int_Handler to fix Logitech 3rd
;*   04/28/95  D119826     CHGTM  Added code to support shared interrupts for
;*                                for serial mouse
;**************************************************************************



.386p

.xlist
        include basemaca.inc
        include mouse.inc
        include singleq.inc
        include infoseg.inc
        include devhlpP.inc            ;76711
.list

;*
;*    External Mouse Module Data References
;*

       extrn  FgndSessn            : byte
       extrn  MEvent               : byte
       extrn  SInt_Packet          : byte
       extrn  SQDD                 : byte
       extrn  DeviceData           : byte
       extrn  gMEvent              : byte
       extrn  Enable_8259          : byte
       extrn  Disable_8259         : byte
       extrn  Enable_28259         : byte
       extrn  Disable_28259        : byte
       extrn  SynchMask            : byte   ;@V2.0XXX03
       extrn  SynchFlag            : word   ;@V2.0XXX03
       extrn  MiddleButFlag        : byte   ;@V2.1XXX03
       extrn  Relaxed              : byte

       extrn  Last_Event           : word
       extrn  ByteCount            : word
       extrn  DevStatus            : word
       extrn  PortBase             : word
       extrn  InportAddr           : word
       extrn  PrevEvent            : word
       extrn  First_Port           : word
       extrn  GDT_Seg              : word
       extrn  HotPlugHandle        : dword  ;@V2.0XXX02

;;**************   Security Begin

       extrn  Security_Enable      : byte
       extrn  Security_Off         : dword  ; Point to data offset
       extrn  Security_DS          : word   ; Load Security's DS

;;**************   Security End

       extrn  Device_Help          : dword

       extrn  MSEVDDEntry          : fword

       extrn  CalcRelative         : near
       extrn  Update_Ptr           : near

       extrn  GIDC_Entry           : far
       extrn  QueueWrite           : far


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

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

       PUBLIC  CalcPixelMvmnt
       PUBLIC  CalcPtrPos
       PUBLIC  CalcProtThreshold
       PUBLIC  ReportProtectEvent
       public  PDI_Int_Handler
       public  MSS_Int_Handler
       public  Disable_Com
       public  Enable_Com
       public  INP_Int_Handler
       public  BUS_Int_Handler



;******************************************************************
;*
;* FUNCTION NAME  :  CalcPixelMvmnt
;*
;* DESCRIPTION    :  This routine calculates the number of pixels
;*                   moved on the display from the input motion and
;*                   movement parameters.  X below is the pixel motion
;*                   calculated.
;*
;*                   X = ((motion * 8) + MickeyRemainder)/ScaleFactor
;*                        Remainder saved as new MickeyRemainder
;*
;* INPUT          : stack frame as follows on entry
;*
;*                     Top --> return address       word
;*                             MickeyRemainder      word
;*                             RawMotion            word
;*                             ScaleFactor          word
;*
;* OUTPUT         :  ax is the number of pixels moved.
;*
;* RETURN-NORMAL  : NONE.
;*
;*
;* RETURN-ERROR   : NONE.
;*
;*
;*********************************************************************
;* PSEUDOCODE :
;*
;* BeginSub  CalcPixelMvmnt
;*
;* IF <there was raw motion>
;*    A1 <- ((motion * 8) + MickeyRemainder)/ScaleFactor
;*    MickeyRemainder <- remainder from above equation
;* ELSE
;*    A1 <- 0
;* ENDIF
;*
;* return
;*
;* EndSub  CalcPixelMvmnt
;*
;***********************************************************************/

CalcPixelMvmnt  proc  near

MickeyRemain  equ     <(word ptr [bp+4])>
RawMotion     equ     <(word ptr [bp+6])>
ScaleFactor   equ     <(word ptr [bp+8])>

       enter 0,0

       mov  ax, RawMotion            ; get raw motion
       .if <ax ne 0>                 ; if there was motion
          shl  ax,3                  ; calculate number of pixels to scale
          add  ax, MickeyRemain      ; add in the remainder
          cwd
          idiv ScaleFactor
          mov  MickeyRemain, dx      ; save new remainder
       .endif

       leave
       ret

CalcPixelMvmnt  endp

;***************************************************************************
;*
;* FUNCTION NAME  :  CalcProtThreshold
;*
;* DESCRIPTION    :  This routine does the threshold calculations for
;*                   protect mode.  This is a 2-level calculation.
;*                   The 2nd level is always disabled for text modes.
;*
;* INPUT          : stack frame as follows on entry
;*
;*                    Top --> return address       word
;*                            RawMotion            word
;*                    ax is the base number of pixels moved
;*
;* OUTPUT         :   ax is the number of pixels moved after thresholding
;*
;* RETURN-NORMAL  : NONE.
;*
;*
;* RETURN-ERROR   : NONE.
;*
;*
;***************************************************************************
;* PSEUDOCODE :
;*
;* BeginSub  CalcProtThreshold
;*
;* IF <threshold calcs are enabled>
;*    IF <1st level reached>
;*       ThresholdMultiplier <- 1st level multiplier
;*       IF <display mode is graphics  AND
;*           second level reached>
;*          ThresholdMultiplier <- 2nd level multiplier
;*       ENDIF
;*       AX = PixelMotion * ThresholdMultiplier
;*    ENDIF
;*  ENDIF
;*
;* EndSub  CalcProtThreshold
;*
;**************************************************************************

CalcProtThreshold  proc  near

RawMotion     equ     <(word ptr [bp+4])>

       enter 0,0

       mov  cx, RawMotion                  ; get the raw motion
       test cx, 8000h                      ; if the motion was negative
       jz   cpt1                           ; then get the absolute value
       neg  cx                             ; convert negative to positive
cpt1:
       test [si].D_Status, ThrhldDsbld     ; if threshold calcs enabled
       .if <z>                             ;
          .if <cx g [si].Level1>           ; if 1st level is met
             mov  bx, [si].Lvl1Mplr        ; set multiplier
             test [si].MType, Graphics     ; if a graphics mode is active
             .if <nz> AND                  ; and the second level
             .if <cx g [si].Level2>        ; is met
                mov  bx, [si].Lvl2Mplr     ; set the 2nd level multiplier
             .endif                        ; end 2nd level test
             imul bx                       ; apply the multiplier
             cmp  dx,0
             .if <ne> AND                  ; if overflow...
             cmp  dx,0FFFFh
             .if <ne>
                mov ax,08000h              ; set maximum neg value UNLESS...
                test dx,8000h
                .if <z>                    ; overflow is positive, in which case
                   mov ax,7FFFh            ; set maximum positive value.
                .endif
             .endif
          .endif                           ; end 1st level test
       .endif                              ; end thrshld calcs enabled test

       leave
       ret

CalcProtThreshold  EndP


;************************************************************************
;*
;* FUNCTION NAME  :  CalcPtrPos
;*
;* DESCRIPTION    :  This routine calculates the new pointer position.
;*                   It uses the cellsize parameter to figure out the
;*                   new display position.
;*
;* INPUT          : stack frame as follows on entry
;*
;*                    Top --> return address       word
;*                            CellRemainder        word
;*                            CellSize             word
;*                            CurrentPointerPos    word
;*                            Resolution           word
;*                    ax is the number of pixels moved after thresholding
;*
;* OUTPUT         :   ax is the new pointer position.
;*
;* RETURN-NORMAL  : NONE.
;*
;*
;* RETURN-ERROR   : NONE.
;*
;*
;*************************************************************************
;* PSEUDOCODE :
;*
;* BeginSub  CalcPtrPos
;*
;*
;* EndSub  CalcPtrPos
;*
;*************************************************************************

CalcPtrPos  proc  near

CellRemain    equ     <(word ptr [bp+4])>
CellSize      equ     <(word ptr [bp+6])>
Ptr_Coord     equ     <(word ptr [bp+8])>
Resolution    equ     <(word ptr [bp+10])>

       enter 0,0

       add  ax, CellRemain         ; add previous cell mvmnt remainder
       cwd                         ; convert to a dword
       idiv CellSize               ; divide by cell size of display mode
       mov  CellRemain, dx         ; save new remainder

       add  ax, Ptr_Coord          ; get current ptr pos
       dec  Resolution             ; base current resolution at 0
       .if <ax gt Resolution>      ; if new pos is > resolution
          mov  ax, Resolution      ; then set to max value
          mov  CellRemain, 0
       .elseif <ax lt 0>           ; else if new pos is < 0 then
          xor  ax, ax              ; set new pos to 0 and
          mov  CellRemain, 0
       .endif

       leave
       ret

CalcPtrPos  EndP


;************************************************************************
;*
;* FUNCTION NAME  :  ReportProtectEvent
;*
;* DESCRIPTION    :  This routine reports a protect mode mouse event.
;*                   It can be reported to one of three places.
;*                   1) a monitor chain, 2) the singleq device driver,
;*                   or 3) the event queue directly.
;*
;* INPUT          :  MEvent structure is setup with the mouse event.
;*
;*                   stack frame:   top  -> return address  word
;*                                          Event type      word
;*                                          Row             word
;*                                          Col             word
;*
;*                   DS:SI - SGCB
;*
;* OUTPUT         :  none.
;*
;* SIDE EFFECTS   :  GP regs not preserved.
;*
;* RETURN-NORMAL  : NONE.
;*
;*
;* RETURN-ERROR   : NONE.
;*
;************************************************************************

Procedure ReportProtectEvent

       ArgVar NCol       WORD        ;
       ArgVar NRow       WORD        ;
       ArgVar ReportType WORD        ; 0-relative event, 1-absolute

;*
;* Determine if the event is reportable or not.  If the initial test against
;* the session event mask fails, the event may still be reportable becuase
;* there may have been a button up transition on a reportable button event.
;*

       EnterProc

       mov  ax, [si].E_Mask             ; test this event against the session
       and  ax, fs:MEvent.Mon_EMask     ; event mask to see if reportable

       .if <ax eq 0>                    ; if event is not reportable then

          mov  dx, fs:Last_Event.Mon_EMask ; get last event
          mov  di, fs:MEvent.Mon_EMask     ; get this event
          mov  cl, 1                       ; start with button 1
          mov  bx, 0006h                   ; initial button screen mask


          .while <cl le fs:DeviceData.NumButt>  ; do for all buttons
             test dx, bx                ; see if last event had button down
             .if  nz                    ; if it was then see if
               test di, bx              ; this event has same button up and
               .if  z  AND              ; if that button event is reportable
               test [si].E_Mask, bx     ; then set ax to 1 to indicate
               .if  nz                  ; that this event is
                 or   ax, 1             ; reportable.
                 .leave                 ; and leave the while loop
               .endif                   ;
             .endif                     ;
             inc  cl                    ; next button
             shl  bx, 2                 ; make next button mask
          .endwhile                     ; end while loop checking buttons

       .endif                           ; end non reportable event test

;*
;* Now report the event if needed.  If the event is reportable then AX will
;* be non-zero.
;*

       .if <ax ne 0> NEAR               ; if the event is reportable

;*
;* Now see if this event is the same as the last event.  If not then
;* report it, otherwise throw it away.
;*

          mov  bx, fs:MEvent.Mon_EMask            ; Get this Event's
          mov  cx, fs:MEvent.Mon_Row_Pos          ; Event Mask, Row
          mov  dx, fs:MEvent.Mon_Col_Pos          ; And Column Pos'

          lea  di, Last_Event                     ; Get pointer to last event

          .if <fs:[di].Mon_EMask   ne bx> OR near ; if last event is not a
          .if <fs:[di].Mon_Row_Pos ne cx> OR near ; dup of this event then
          .if <fs:[di].Mon_Col_Pos ne dx> OR near ; OR event is to be reported
          .if <ReportType eq 1>              near ; regardless, then report it

             push si                           ; Save session CB Offset
             push ds
             mov  ax, fs                       ; Setup ES
             mov  es, ax                       ; to DS
             mov  ds, ax

             lea  si, MEvent                   ; offset to current event
             lea  di, Last_Event               ; last event buffer.
             mov  cx, MRec_Size                ; size of event
             rep  movsb                        ; save this event as last event

             pop  ds
             pop  si                           ; Restore SG CB Offset

;*
;* This section actually reports the event to the appropriate place.  If
;* monitors are registered then the event is sent down the monitor chain for
;* the session.  Monitor registration restrictions are handled elsewhere.
;* If no monitors are registered then the event is sent directly to either
;* a protect mode event queue, the SingleQ DD, or to the VDD for a VDM session.
;*

             push ds                       ; Save DS value Around Call
             push si                       ; Save SI value Around Call

QueueEvent:
             .if <[si].Chain_Size eq 0> NEAR  ; If no monitors are registered

                test [si].D_Status, SQ_Mode   ; Check to if SQ mode active
                .if nz near                   ; if active then

                   xor  cx, cx                ; Clear Save/Restore Count

                   push si                           ; Save SG CB Offset
                   mov  si, offset MEvent.Mon_Emask  ; Get event offset

                   mov  ah, 02h               ; Specify Mouse DD calling
                   mov  al, ElRec_Size        ; Specify data rec size
                   mov  bh, 02h               ; Specify TimeStamp offset

                   mov  bl, 02h               ; Specify Write Function

                   push fs
                   push es                    ; Save user data selector
                   push SQDD.ProtDS           ; Get SQ DD DS selector
                   pop  es                    ; Load into ES for call
                   call dword ptr fs:SQDD.ProtEntry  ; Invoke SQ DD func
                   pop  es                    ; Restore selector
                   pop  fs
                   pop  si                    ; Restore SG CB offset

                   .if <ax eq Error_SQ_Not_In_Mode>   ; If SQ not taking data
                      and  [si].D_Status, NOT SQ_Mode ; Reset SQ Mode
                      jmp  QueueEvent                 ; Go queue the data
                   .endif                             ; SQ Write done

                .else                                 ; not in SQ mode

                   test [si].D_Status, Busy_Mask    ; see if que is busy
                   .if <z>                          ; if not then write record
                      push fs                       ; selector of event record
                      push offset MEvent.Mon_Emask  ; offset of event
                      call QueueWrite               ; go put in queue
                   .endif

                .endif

             .else                         ; monitors registered
                mov  ax, [si].Chain_Hdle   ; SG Mon Chain Handle
                mov  si, OFFSET MEvent     ; Addr of Temp Event Record
                push ds
                push fs
                pop  ds
                mov  cx, MRec_Size         ; # of bytes in Temp Record
                mov  dh, 1                 ; No_Wait option = 1
                mov  dl, DevHlp_MonWrite   ; Specify MonWrite Function
                call Device_Help           ; Invoke MonWrite Function
                pop  ds
             .endif                        ; end mon reg test

             pop  si                       ; Restore SI value After Call
             pop  ds                       ; Restore DS value After Call

          .endif                           ; duplicate event Test
       .endif                              ; reportable event test

       .if <[si].Chain_Size eq 0>          ; If no monitors are registered

          .if <bit [SI].D_Status nz MickeyData>
             mov  cx, NCol
             mov  dx, NRow
          .else
             mov  cx, fs:MEvent.Mon_Col_Pos   ; get new column
             mov  dx, fs:MEvent.Mon_Row_Pos   ; net new row
          .endif

          call Update_Ptr                  ; update the pointer image
       .endif

       LeaveProc
       ret

EndProc ReportProtectEvent, NoCheck

;************************************************************************
;*
;* FUNCTION NAME  :  PDI_Int_Handler
;*
;* DESCRIPTION    :  Mouse device Interrupt Handler.
;*
;*                   Reads mouse interrupts, translates to common
;*                   format, and sends them to the independent DD.
;*
;* ENTRY POINT    :  PDI_Int_Handler     LINKAGE:  CALL FAR
;*
;* INPUT          :  None, except data from mouse device
;*
;* RETURN-NORMAL  :  Always, carry clear -- our interrupt.
;*
;* RETURN-ERROR   :  N/A.
;*
;* EFFECTS        :  Stack is clean on return.  AX, BX, CX, DX, SI,
;*                   and DI registers are changed.
;*
;* INTERNAL REFERENCES:
;*    ROUTINES:  None.
;*
;* EXTERNAL REFERENCES:
;*    ROUTINES:  NONE.
;*    DevHlps:  See individual support routines.
;*
;************************************************************************
;*
;*
;* The IBM mouse interrupts in 3 byte data packets.
;*
;* Byte 1 = Status    Bit 7 = Y Data OverFlow
;*                            0 = No OverFlow
;*                            1 = OverFlow
;*                    Bit 6 = X Data OverFlow
;*                            0 = No OverFlow
;*                            1 = OverFlow
;*                    Bit 5 = Y Data Sign
;*                            0 = Positive
;*                            1 = Negative
;*                    Bit 4 = X Data Sign
;*                            0 = Positive
;*                            1 = Negative
;*                    Bit 3 = Reserved   ( Set by hardware and used as mask
;*                    Bit 2 = Reserved     to indicate first byte of packet
;*                            ;@V2.1XXX03               OR
;*                            ;@V2.1XXX03  If logitech 3 button mouse, bit 2
;*                            ;@V2.1XXX03  is Middle Button Status)
;*
;*                    Bit 2 = Middle Button Status
;*                            0 = Not Pressed
;*                            1 = Pressed
;*                    Bit 1 = Right Button Status
;*                            0 = Not Pressed
;*                            1 = Pressed
;*                    Bit 0 = Left Button Status
;*                            0 = Not Pressed
;*                            1 = Pressed
;*
;* Byte 2 = X Data    (Data Value)
;* Byte 3 = Y Data    (Data Value)
;************************************************************************

PDI_Int_Handler  proc  far

       sti                              ; Enable system interrupts

       in   al, 64h                     ; Read Controller Status Register

       and  al, 21h                     ; Get AOBF,OBF and TIMEOUT bits only
       test al, 21h                     ; If (OBF & Aux OBF) int is ours
       jnz  pdi_int                     ; Process the interrupt

       stc                              ; Tell Int Mgr not our interrupt
       jmp  pdi_exit                    ; Exit the interrupt handler

pdi_int:
     ; IssueEOI                                             Remove 76711
       cli                                     ;            Add    76711
       DevEOI    <DeviceData.IRQ>,Device_Help  ;            Add    76711

       in  al, 60h                      ; Get data from 8042 data register
                                        ; @V2.1XXX04 begin
       .if <al eq 0aah>                 ; Is this a possible repower event?
          or  SynchFlag, HOTPLUG1       ; Indicate stage one of Hot Plug test
       .else
          test SynchFlag, HOTPLUG1      ; If this is second stage of testing
          .if <nz> AND                  ; for a mouse repower event?
          .if <al eq 0> AND             ; Has the Mouse POR'd stage 2?
          .if <bit SynchFlag z HOTPLUG2>; Is context hook already armed?
             or   SynchFlag, HOTPLUG2   ; serialize DevHlp_ArmCtxHook call
                                        ; @V2.1XXX04 end
             .if <HotPlugHandle ne 0>   ; Zero handle causes problems
                mov  eax, 0
                mov  ebx, HotPlugHandle
                mov  ecx, 0FFFFFFFFh
                mov  dl,  DevHlp_ArmCtxHook
                call Device_help        ; Call HotPlug routine at strat time
             .else
                and  SynchFlag, HOTPLUG ; Clear SynchFlag of hot plug events
             .endif                     ; @V2.1XXX04

             mov  ByteCount,0           ; Reset packet count
             clc                        ; Indicate this is our interrupt
             jmp  pdi_exit              ; EXIT since this is not a valid event
          .else
             and  SynchFlag, HOTPLUG    ; Clear SynchFlag of hot plug events
          .endif                        ; @V2.1XXX04


       .endif

test_synch:
       .if <Relaxed eq 0> AND           ; if we're not relaxed on sync...
       .if <ByteCount eq 0> AND         ; Check for first Byte of packet
       .if <bit SynchFlag z HOTPLUG1>   ; This is NOT a HOTPLUG event
         .if <bit SynchFlag z SYNCHMASKSAVED> ;If first interrupt received
            or   SynchFlag, SYNCHMASKSAVED ; Set global flag synch bits saved
            mov  SynchMask, al          ; Save synch bits for this device

            .if <DeviceData.NumButt eq 3>   ; if three button mouse
               and  SynchMask, THREE_BUTT_MASK ; Mask off unwanted bits
            .else
               and  SynchMask, TWO_BUTT_MASK   ; Mask off unwanted bits
            .endif                      ; @V2.1XXX03

         .endif                         ; @V2.0XXX01

         mov  bl, al                    ; Preserve data byte

         .if <DeviceData.NumButt eq 3>  ; if three button mouse
            and  bl, THREE_BUTT_MASK    ; Remove unwanted bits
         .else
            and  bl, TWO_BUTT_MASK      ; Remove unwanted bits
         .endif                         ; @V2.1XXX03

         cmp  bl, SynchMask             ; Check for bit pattern
         jz   in_synch                  ; Jump, packet in synch with first byte
         inc  ByteCount                 ; Out if synch, maybe the next one

       .endif                           ; @V2.0XXX01

in_synch:
       mov  di, ByteCount               ; get current byte count
       mov  gMEvent[di], al             ; save data in packet
       inc  ByteCount                   ; increment # bytes received

pdi_chk_pack:                           ;P75
       .if <ByteCount eq PDI_PACKETSIZE>  NEAR  ; If start of packet
          mov  ByteCount, 0             ; Reset byte counter
          xor  cx, cx                   ; clear event holder
          mov  ah, byte ptr gMEvent[0]  ; get button status
          shr  ah, 1                    ; put button 1 status in the carry
          jnc  pb1up                    ; if no carry button 1 is not pressed
          or   cx, 0002h                ; otherwise set w/motion but 1 event
pb1up:    shr  ah, 1                    ; put button 2 status in the carry
          jnc  pb2up                    ; if no carry button 2 is not pressed
          or   cx, 0008h                ; otherwise set w/motion but 2 event
pb2up:
          .if <DeviceData.NumButt eq 3>
            test ah, 1                  ; test bit 0 for button 3 down was bit 2
            jz  pb3up                   ; if zero, button 3 is not pressed
            or   cx, 0020h              ; otherwise set w/motion but 3 event
          .endif                        ; @V2.1XXX03

pb3up:    mov  bh, byte ptr gMEvent[1]  ; get column movement data
          mov  bl, byte ptr gMEvent[2]  ; get row movement data
          test ah,20h                   ; row overflow?
          jz   colovr                   ; no overflow... test column mickeys now
          mov  bl,0FFh
colovr:   test ah,10h                   ; column overflow?
          jz   trunmik                  ; no overflow... just truncate to 8 bits
          mov  bh,0FFh
trunmik:  or   bx,8080h                 ; make negative until proven otherwise
          test ah,4h                    ; is motion to the left?
          jnz  b1lt0
          and  bh,7Fh                   ; nope... clear sign bit
b1lt0:    test ah,8h                    ; is motion down?
          jnz  b2lt0
          and  bl,7Fh                   ; nope... clear sign bit

b2lt0:    neg  bl                       ; make down positive, up negative
          cmp  bx, 0                    ; see if no motion
          jne  pmove                    ; if mvmnt go check for button presses
          shl  cx, 1                    ; else make event a w/o motion event
          jmp  pdi1                     ; and go process the packet
pmove:    cmp  cx, 0                    ; there was motion, any buttons pressed
          jne  pdi1                     ; if not go process the packet
          inc  cx                       ; make event a pure motion event
pdi1:     Send_Packet                   ; process the packet
       .endif                           ; end complete event packet test

       clc                              ; our interrupt

pdi_exit:
       ret                              ; return to intr hndlr

PDI_Int_Handler  endp


;************************************************************************
;*
;*  FUNCTION NAME  :  MSS_Int_Handler
;*
;*  DESCRIPTION    :  Mouse device Interrupt Handler.
;*
;*                    Reads mouse interrupts, translates to common
;*                    format, and sends them to the independent DD.
;*
;*  ENTRY POINT    :  MSS_Int_Handler   LINKAGE:  CALL FAR
;*
;*  INPUT          :  None, except data from mouse device
;*
;*  RETURN-NORMAL  :  Always, carry clear -- our interrupt.
;*
;*  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:  See individual support routines.
;*
;*************************************************************************
;*
;*      The Microsoft Serial Mouse returns a 3 byte packet whenever the
;*      hardware changes state (movement, button press, button release).                                       *
;*
;*         Byte 1:  B7 : Undefined
;*                  B6 : 1 = Sync bit.  Marks 1st byte of packet OR  ; @V2.1XXX03
;*                       indicates Middle button status (1 = depressed)
;*                  B5 : Button 1 status (1 = depressed)
;*                  B4 : Button 2 status (1 = depressed)
;*                  B3-B2 : 2 high order bits of Delta-Y
;*                  B1-B0 : 2 high order bits of Delta-X
;*
;*         Byte 2:  B7-B6 : Undefined
;*                  B5-B0 : 6 low order bits of Delta-X
;*
;*         Byte 3:  B7-B6 : Undefined
;*                  B5-B0 : 6 low order bits of Delta-Y
;*
;*      Logitech 'M' series three button mouse uses a fourth   ; @V2.1XXX03
;*      data byte to pass the middle button status.
;*
;*         Byte 4:  B7-B6 : 0
;*                     B5 : Button 3 status (1 = depressed)
;*                  B4-B2 : 0
;*                  B1-B0 : Undefined
;*
;*************************************************************************

MSS_Int_Handler  Proc  Far


     ; D119826
     ; D119826 Find out if the interrupt is ours

     ReadAsync                      ; D119826
     jnc  MSS01                     ; D119826 - ours, continue
     ret                            ; D119826 - no, return

       ; issue EOI and disable the mouse IRQ

MSS01:                                ; D119826 - Added label
       push ax                        ; D119826 - save data from readasync

       call Disable_Com               ; disable the device 1st
     ; IssueEOI                                             Remove 76711
       cli                                     ;            Add    76711
       DevEOI    <DeviceData.IRQ>,Device_Help  ;            Add    76711

       pop ax                         ; D119826 - restore data

       sti                            ; tmp hack joeceli


;*
;* Check the read packet first, then check initialization request blocks.
;*

;* D119826 - Already got data - commented out
;*       ReadAsync                      ; !! read interrupt data


;*
;* If we get a Sync Byte in the middle of building an interrupt packet
;* without an error we have encountered the 16550 data error.  Latching
;* generates a RCV interrupt which is lost.  The error is generated
;* on the next data byte.
;*
;* LOGITECH 3rd BUTTON SUPPORT:
;*    The Logitech M+ protocol for 3rd button support is hard to support...
;* Its three bytes most of the time, with a fourth byte sent only when there
;* is a 3rd button event (or motion with 3rd down).  We have to send our packet
;* after three bytes since we can't tell if a fourth is coming, so we implement
;* the following finite state machine.  If GetStatus gets a byte which doesn't
;* have the sync bit set, we then check to verify it is really a 'Logi4' data
;* byte.  If it really is see if the button changed state, if it hasn't changed
;* state then we know we have motion with the 3rd button down and we blow off
;* this data byte.  If the button has changed state though we send another
;* packet indicating a 3rd button event without movement.  Hopefully PM won't
;* care that there can never be a 3rd button transition and movement in the
;* same packet.  We save the state of the 3rd button and always insert it into
;* the packet we send up after 3 bytes, so that PM sees the 3rd button in a
;* consistent state with real life.
;*
;*                     |
;*                    \|/
;*             +-->/  Get  \----->/  Get  \
;*             |   \Status /      \Logi 4 /
;*             |       |              |
;*             |      \|/             |
;*             |   /  Get  \          |
;*             |   \Byte 2 /          |
;*             |       |              |
;*             |      \|/             |
;*             |   /  Get  \          |
;*             |   \Byte 3 /          |
;*             |       |              |
;*             |      \|/             |
;*             |   / Send  \<---------+
;*             |   \Packet /
;*             |       |
;*             +-------+
;*
;* Transition           When
;* GetStat->GetLogi     GetStat has rcvd byte with no syncbit && buttons == 3
;*
;* GetStat->GetByte2    GetStat has rcvd a byte with syncbit
;*
;* GetByte2->GetByte3   GetByte2 has rcvd a byte
;*
;* GetByte3->SendPack   GetByte3 has rcvd a byte
;*
;* SendPack->GetStat    Packet has been sent off
;*
;* !GetStat->GetStat    Any state rcving byte with Syncbit resets to GetStat
;*
        mov     cx,ByteCount
        cmp     cx,0
        jne     notb0
        jmp     getstatus               ;needed since jmp much larger than 127
notb0:  cmp     cx,1
        jz      getbyte2
;****************************************************************************
;*** GETBYTE3 State
;****************************************************************************
getbyte3:
        test    al,SYNCBIT              ;We don't want to see a sync!
        jnz     hasta                   ;BZZZZT! Out of sync!
        mov     gMEvent[2],al           ;Packet is now complete!
;****************************************************************************
;*** SENDPACK State
;****************************************************************************
sendpacket:
        mov     ByteCount,0             ;Ready to build another packet!
;*
;* Button event is in this format:  US12YYXX where 1=depressed.
;* The event mask is built using this byte.  Each button status is rotated
;* into the carry flag.  If the carry flag is 0 then the corresponding
;* button event for button pressed with motion is set in cx.  After all
;* buttons have been checked the motion counters are calculated.  If there
;* was no motion and there was a button depressed then cx is shifted to
;* put the button events in the without motion format.
;*
        mov     ah,gMEvent[0]         ; get button and motion bits
        mov     al,byte ptr gMEvent[1] ; get column motion
        shl     al,2                  ; clear undefined upper 2 bits
        shr     ax,2                  ; put high order bits in al
        mov     bh,al                 ; save col motion in bh
        mov     al,byte ptr gMEvent[2] ; get row motion
        shl     al,2                  ; clear undefined upper 2 bits
        shr     ax,2                  ; put high order bits in al
        mov     bl,al                 ; save row motion in bl
        xor     cx,cx                 ; clear register to build event
        shr     ah,1                  ; Put butt 2 stat in cy flag
        jnc     sb2up                 ; if cy is not set but 2 is up
        or      cx,0008h              ; but 2 is down so set event bit
sb2up:  shr     ah,1                  ; put but 1 stat in cy flag
        jnc     sb1up                 ; if cy is not set but 1 is up
        or      cx,0002h              ; but 1 is down so set event bit
sb1up:
; At this point our packet is complete for 2 buttons... we need to add 3rd
; button, and possibly shift to indicate motion.
        or      cl,MiddleButFlag      ; add state of middle button
sb3up:  cmp     bx,0                  ; see if no column movement
        jne     smove                 ; skip if there was
        shl     cx,1                  ; no mvmnt, cnvrt to w/o format
        jmp     ser1                  ; continue (exit if structure)
smove:  cmp     cx,0                  ; there was mvmnt, any buts down?
        jne     ser1                  ; if so then continue
        inc     cx                    ; no buts dwn, motion only event
ser1:   Send_Packet                   ; macro to process int data
        jmp     finito
;****************************************************************************
;*** GETBYTE2 State
;****************************************************************************
getbyte2:
        test    al,SYNCBIT              ;We don't want to see a sync!
        jnz     hasta                   ;BZZZZT! Out of sync!
        mov     gMEvent[1],al           ;Build that packet!
        inc     ByteCount
        jmp     finito
;****************************************************************************
;*** GETSTATUS State
;****************************************************************************
getstatus:
        test    al,SYNCBIT              ;We *better* be in sync!
        jz      ntsync                  ;nope... could it be Logi-4???
        mov     gMEvent[0],al           ;Build that packet!
        inc     ByteCount
        jmp     finito
ntsync: cmp     DeviceData.NumButt,3    ;3 button mouse?
        jne     hasta                   ;nope... we're just plain out of sync
        test    al,11011100b            ;is it *really* a logi-4?
        jnz     hasta                   ;nope...
;****************************************************************************
;*** GETLOGI4 State
;****************************************************************************
        mov     bl,MiddleButFlag
        and     al,00100000b            ;isolate middle button state
        mov     MiddleButFlag,al        ;indicate button status
        xor     bl,MiddleButFlag
        je      hasta                   ;no change in button state
        and     gMEvent[0],0F0h         ;clear out motion counts
        xor     bx,bx
        mov     gMEvent[1],bl           ; packet with 0 column motion
        mov     gMEvent[2],bl           ; packet with 0 row motion
        jmp     sendpacket
hasta:  mov     ByteCount,0             ;Blow off, and reset for next byte
finito: call    Enable_Com              ; make sure IRQ is enabled
        clc                             ; our interrupt
        ret                             ; return to intr hndlr

MSS_Int_Handler  EndP

;************************************************************************
;*
;* FUNCTION NAME :  Disable_Device
;*
;* DESCRIPTION   :  Disable the mouse IRQ level.
;*
;* FUNCTION      :  Disables the mouse IRQ level at the 8259.
;*
;* ENTRY POINT   :  Disable_Device      LINKAGE:  CALL NEAR
;*
;* INPUT         :  AX = function code
;*                  DS = our DS
;*                  ES = callers DS
;*
;* RETURN-NORMAL :  Always, Mouse IRQ level disabled.
;*
;* 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:  None.
;*
;************************************************************************

Disable_Com  Proc  Near

       pushf                           ; save state of IF
       cli                             ; Hold interrupts for 8259 Update

; #81365 WHH start

ifndef SMP
       in   al, 21h                    ; Get current Interrupt Mask
       or   al, Disable_8259           ; Set Mouse Interrupt IRQ Bit - ON
       out  21h, al                    ; Reset 8259 holding Mouse ints
       in   al, 0a1h                   ; Get current Interrupt Mask
       or   al, Disable_28259          ; Set Mouse Interrupt IRQ Bit - ON
       out  0a1h, al                   ; Reset 8259 holding Mouse ints
else
       push    dx
       mov     dl, DevHlp_SetIRQMask
       mov     al, DeviceData.IRQ
       mov     ah, 1
       call    Device_Help
       pop     dx
endif

; #81365 WHH end

       popf                            ; restore interrupt flag
       ret

Disable_Com  EndP

;************************************************************************
;*
;*  FUNCTION NAME  :  Enable_Device
;*
;*  DESCRIPTION    :  Enable mouse IRQ level.
;*
;*  FUNCTION       :  Enables the mouse device IRQ level at the 8259.
;*
;*  ENTRY POINT    :  Enable_Device     LINKAGE:  CALL NEAR
;*
;*  INPUT          :  AX = function code
;*                    DS = our DS
;*                    ES = callers DS
;*
;*  RETURN-NORMAL  :  Always, mouse IRQ enabled.
;*
;*  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:  None.
;*
;*************************************************************************

Enable_Com  Proc  Near

       pushf                           ; save state of IF
       cli                             ; Hold interrupts for 8259 Update

; #81365 WHH start

ifndef SMP
       in   al, 21h                    ; Get current Interrupt Mask
       and  al, Enable_8259            ; Set Mouse Interrupt IRQ Bit - OFF
       out  21h, al                    ; set innterrupt mask
       in   al, 0a1h                   ; Get current Interrupt Mask
       and  al, Enable_28259           ; Set Mouse Interrupt IRQ Bit - OFF
       out  0a1h, al                   ; set innterrupt mask
else
       push    dx
       mov     dl, DevHlp_SetIRQMask
       mov     al, DeviceData.IRQ
       mov     ah, 0
       call    Device_Help
       pop     dx
endif

; #81365 WHH end

       popf                            ; restore interrupt flag state
       ret

Enable_Com  EndP

;************************************************************************
;*
;*  FUNCTION NAME :  INP_Int_Handler
;*
;*  DESCRIPTION   :  Mouse device Interrupt Handler.
;*
;*                   Reads mouse interrupts, translates to common
;*                   format, and sends them to the independent DD.
;*
;*  ENTRY POINT   :  MSS_Int_Handler   LINKAGE:  CALL FAR
;*
;*  INPUT         :  None, except data from mouse device
;*
;*  RETURN-NORMAL :  Always, carry clear -- our interrupt.
;*
;*  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:  See individual support routines.
;*
;*************************************************************************
;*
;*
;*
;*  When an interrupt occurs, information is
;*  obtained from the interface in the following way:
;*
;*  OUT Address Pointer Port #, Mode Register #
;*  IN  AL, Data Register Port #
;*  OR  AL, Hold Bit #
;*  OUT Data Register Port #, AL
;*   data is now available in the status & data registers
;*
;*  OUT Address Pointer Port #, Status Register #
;*  IN  AL, Data Register Port #
;*   AL now has mouse status in b0-7
;*        Movement status in b6 (1 = movement)
;*        Button 1 status in b2 (1 = down)
;*        Button 3 status in b0 (1 = down)
;*
;*  delta x data is read only if the movement status bit in the
;*  mouse status is set (1), otherwise delta x is set to 0
;*
;*  OUT Address Pointer Port #, Data 1 Register #
;*  IN  AL, Data Register Port #
;*   AL now has 8 bits of delta x in b0-7
;*
;*  delta y data is read only if the movement status bit in the
;*  mouse status is set (1), otherwise delta y is set to 0
;*
;*   OUT Address Pointer Port #, Data 2 Register #
;*  IN  AL, Data Register Port #
;*   AL now has 8 bits of delta y in b0-7
;*
;*  OUT Address Pointer Port #, Mode Register #
;*  IN  AL, Data Register Port #
;*  AND AL, not Hold Bit #
;*  OUT Data Register Port #, AL
;*   interface is now enabled for mouse data
;***************************************************************************

;*
;* Set Hold bit in Mode register.  When the Hold bit is changed from 0 to 1,
;* the following events occur: 1) the INTR signal is reset to 0, 2) the mouse
;* counter values are saved in the Data1 and Data2 registers, 3) the mouse
;* counters are cleared, and 4) mouse status register is updated.  Note that
;* the other bits of the Mode register must remain unchanged.
;*

INP_Int_Handler  proc  far

       ;*
       ;* issue the EOI and disable the IRQ
       ;*

;**    call Disable_Device            ; disable the device 1st
       sti

       MOV  DX, InportAddr             ; DX <-- base port #
       MOV  SI, DX                     ; SI <-- register # register port #
       MOV  AL, INP_MODE_REG           ; AL <-- mode register #
       OUT  DX, AL                     ; point to the InPort mode register
       ADD  DX, INP_DATA1_REG          ; DX <-- data register port #
       IN   AL, DX                     ; AL <-- mode register value
       OR   AL, HOLD_BIT               ; set Hold bit in the mode register,
       OUT  DX, AL                     ;  leave all others unchanged

;*
;* Read the Status register and save it in CL
;*

       XCHG DX, SI                     ; DX <-- register # register port #
                                       ; SI <-- data register port #
       MOV  AL, INP_STATUS_REG         ; AL <-- status register #
       OUT  DX, AL                     ; point to InPort status register
       XCHG DX, SI                     ; SI <-- register # register port #
                                       ; DX <-- data register port #
       IN   AL, DX                     ; AL <-- status register value

       xor  cx, cx                     ; clear event
       mov  ah, al                     ; save status byte
       shr  ah, 1                      ; get button 3 (2) status in cy flag
       jnc  i2up                       ; if no carry button 3 (2) is up
       or   cx, 0008h                  ; else it's down
i2up:  shr  ah, 2                      ; get button 1 status in cy flag
       jnc  i1up                       ; if no carry button 1 is up
       or   cx, 0002h                  ; else it's down
i1up:  test al, MOVEMENT_BIT           ; now see if there was movement
       jnz  imvmt                      ; if there was then go process it
       shl  cx, 1                      ; no move, cnvrt event to no move format
       xor  bx, bx                     ; clear movement registers
       jmp  prcs                       ; go process the event
imvmt: cmp  cx, 0                      ; see if any buttons pressed
       jne  prsd                       ; yes so skip motion only event setting
nprsd: inc  cx                         ; if none then set motion only event
prsd:  xchg dx, si                     ; get request register address
       mov  al, INP_DATA1_REG          ; request data 1 register (delta x)
       out  dx, al                     ; go request DATA 1
       MyIODelay
       xchg dx, si                     ; data register address
       in   al, dx                     ; read delta x value
       mov  bh, al                     ; save col movement in bh
       xchg dx, si                     ; get request register address
       mov  al, INP_DATA2_REG          ; request data 2 register (delta y)
       out  dx, al                     ; go request DATA 2
       MyIODelay
       xchg dx, si                     ; data register address
       in   al, dx                     ; read delta x value
       mov  bl, al                     ; save row movement in bl

;*
;* Reset Hold bit in Mode register.  When the Hold bit is changed from 1 to 0,
;* the following events occur: 1) the Packet Complete bit in the Status
;* register is cleared, and 2) the packet transfer circuitry is re-enabled so
;* that another transfer can occur.  Note that the other bits of the Mode
;* register must remain unchanged.
;*

prcs:

       XCHG DX, SI                     ;  DX <-- register # register port #
                                       ;  SI <-- data register port #
       MOV  AL, INP_MODE_REG           ;  AL <-- mode register #
       OUT  DX, AL                     ;  point to the InPort mode register
       MOV  DX, SI                     ;  DX <-- data register port #
       IN   AL, DX                     ;  AL <-- mode register value
       AND  AL, NOT_HOLD_BIT           ;  reset Hold bit in mode register,
       OUT  DX, AL                     ;   leave all others unchanged

       CMP  CX,0                       ; null mouse event?
       JNE  int10                      ; NO, go ahead process it

       CMP  PrevEvent,0                ; previous mouse event is null?
       JE   int20                      ; YES, ignore this event

int10: MOV  PrevEvent,CX               ; Save mouse event
       Send_Packet                     ; go process the packet

int20: cli                             ; make sure ints disabled.
     ; IssueEOI                        ; Issue the EOI      Remove 76711
       DevEOI    <DeviceData.IRQ>,Device_Help  ;            Add    76711
;**    call Enable_Device              ; make sure IRQ is enabled

       clc                             ; our int

       ret                             ; return to intr hndlr

INP_Int_Handler  endp

;************************************************************************
;*
;*  FUNCTION NAME  :  BUS_Int_Handler
;*
;*  DESCRIPTION    :  Mouse device Interrupt Handler.
;*
;*                    Reads mouse interrupts, translates to common
;*                    format, and sends them to the independent DD.
;*
;*  ENTRY POINT   :  MSS_Int_Handler   LINKAGE:  CALL FAR
;*
;*  INPUT         :  None, except data from mouse device
;*
;*  RETURN-NORMAL :  Always, carry clear -- our interrupt.
;*
;*  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:  See individual support routines.
;*
;*************************************************************************
;*
;*
;*
;*  When an interrupt occurs, the following
;*  information is available via the interface:
;*
;*  OUT Request Port #, 90H
;*  IN  AL, Data Port #
;*    AL now has low 4 bits of delta x in b0-3
;*
;*  OUT Request Port #, B0H
;*  IN  AL, Data Port #
;*   AL now has high 4 bits of delta x in b0-3
;*
;*  OUT Request Port #, D0H
;*   IN  AL, Data Port #
;*   AL now has low 4 bits of delta y in b0-3
;*
;*  OUT Request Port #, F0H
;*  IN  AL, Data Port #
;*   AL now has high 4 bits of delta y in b0-3
;*                   Button 1 status in b7 (0 = down)
;*                    Button 2 status in b5 (0 = down)
;*
;*  Read in 4 bytes of info & put into Mouse_Event
;*
;************************************************************************

BUS_Int_Handler  Proc  Far

       ;*
       ;* issue the EOI and disable the IRQ
       ;*

;**    call Disable_Device            ; disable the device 1st
       sti

       MOV  DI, First_Port      ; Port # of parallel mouse
       MOV  SI, DI
       ADD  SI, 2               ; Point to request port

;*
;*  Read in the delta X
;*

       MOV  DX, SI              ; Get ready for OUT instruction
       MOV  AL, Low_X           ; Command to report low-order delta x
       OUT  DX, AL
       MyIODelay
       MOV  DX, DI              ; Get data port #
       IN   AL, DX              ; Read in low-order delta x
       AND  AL, 0FH             ; Retain only low 4 bits
       MOV  CH, AL              ; Save low order 4 bits

       MOV  DX, SI
       MOV  AL, Hi_X            ; Command to report hi-order delta x
       OUT  DX, AL
       MyIODelay
       MOV  DX, DI              ; Get data port #
       IN   AL, DX              ; Read in hi-order delta x

       SHL  AL, 4               ; Move high order bits into position
       OR   AL, CH              ; Get low order bits into AL
       MOV  bh, AL

;*
;*  Now read in the delta Y
;*

       MOV  DX, SI              ; Get ready for OUT instruction
       MOV  AL, Low_Y           ; Command to report low-order delta y
       OUT  DX, AL
       MyIODelay
       MOV  DX, DI              ; Get data port #
       IN   AL, DX              ; Read in low-order delta y
       AND  AL, 0FH             ; Retain only low 4 bits
       MOV  CH, AL              ; Save low order 4 bits

       MOV  DX, SI
       MOV  AL, Hi_Y            ; Command to report hi-order delta y
       OUT  DX, AL
       MOV  DX, DI              ; Get data port #
       MyIODelay
       IN   AL, DX              ; Read in hi-order delta y

       MOV  AH, AL              ; Save Button status
       SHL  AL, 4               ; Move high order bits into position
       OR   AL, CH              ; Get low order bits into AL
       MOV  bl, al

;*
;*  AH is in the following form:
;*     bit  7      button 1 (Left)   status
;*     bit  6      Don't Care
;*     bit  5      button 2 (Right)  status
;*     bit 4-0     Don't Care
;*

;*
;*  convert hardware button mask into software mask and
;*  store back into temp_event record
;*

       XOR  CX, CX              ; Clear CX for software mask

       shl  ah, 1
       jc   b1up
       or   cx, 0002h
b1up:  shl  ah, 2
       jc   b2up
       or   cx, 0008h
b2up:  cmp  bx, 0
       jne  mvmnt               ; skip if there was
       shl  cx, 1               ; no mvmnt, cnvrt to w/o format
       jmp  cnt1                ; continue (exit if structure)
mvmnt: cmp  cx, 0               ; there was mvmnt, any buts down?
       jne  cnt1                ; if so then continue
       inc  cx                  ; no buts dwn, motion only event

cnt1:  MOV  DX, First_Port             ; Load Base Port #
       ADD  DX, 2                      ; Get Request Port #
       SUB  AL, AL                     ; Send 0 to Request Port to
       OUT  DX, AL                     ; Reset interface registers
       MyIODelay

       Send_Packet                     ; macro to process int data

       test DevStatus, DEVICEENABLED   ; see if device already enabled
       .if <z>                         ; if not
          cli                          ; hold ints
;**       call Enable_Device           ; then enable the device
       .endif

     ; IssueEOI                                             Remove 76711
       cli                                     ;            Add    76711
       DevEOI    <DeviceData.IRQ>,Device_Help  ;            Add    76711
       clc                             ; our int

       ret                             ; return to intr hndlr

BUS_Int_Handler  EndP

CSEG  ends
      end
