;/*************************************************************************
;*
;* SOURCE FILE NAME = PDI.ASM
;*
;* DESCRIPTIVE NAME = Pointing Device Interface (PDI) code
;*
;* 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/19/92
;*
;* DESCRIPTION  This file contains the PDI specific routines used
;*              by the generic pointing device driver.
;*
;*              Currently known and supported PDI devices are;
;*
;*              IBM PS/2 Mouse
;*              MS PS/2 Mouse
;*              Logitech PS/2 Mouse
;*              Kensington Expert Mouse (really trackball device)
;*
;* FUNCTIONS    CheckforPDIDevice
;*              Enable_Ints        -Enable keyboard Interface
;*              ResetMouse         -Reset PS/2 mouse.
;*              IsScrnKeypad       -Determine if a ScreenReader 18-key
;*                                   keypad is plugged into PDI port
;*              ResetPrescott      -Reset prescott display
;*              WriteInputBuffer   -Send a byte of data to 8042 (port 60h).
;*              SendToMouse        -Send command to auxillary device
;*              Read8042Data       -Wait until there is data in the output
;*                                  buffer and return it in AL.
;*              GetMouseData       -Read a byte of data to auxillary device
;*              SetSampleRate      -Send the SetSampleRate Command (0f3h)
;*                                   to the Aux device
;*              SetScaling         -Send the SetScaling 2:1 Command (0E7h)
;*              SetResolution      -Send the SetResolution Command (0e8h)
;*                                   to the Aux device.
;*              EnablePDI          -Enable the Aux Device
;*              ClearAuxPort       -Read all Aux port data
;*            WriteControlRegister -Send a command byte to the
;*                                   8042's control register (64h)
;*              PDIInit            -Gets the PDI LID if on ABIOS system
;*
;*
;*
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   04/04/93  @V2.1XXX01  53232  Add support for Logitech middle button
;*   06/10/95  @V3.0PMS01 124938  Added support to allow Inhibit bit for
;*                                password control on 8042 - PM Schoeller
;**************************************************************************




.xlist
       include basemaca.inc
       include mouse.inc
.list

.386p

;*
;*    External Mouse Module Data References
;*

       extrn TranslateMode       : byte
       extrn AUXPortExists       : byte
       extrn DeviceData          : byte
       extrn ABIOS_Mch           : byte
       extrn PrescottDsp         : byte
       extrn ScreenKeypad        : byte
       extrn Init_Time           : byte

       extrn Int_Packet          : word
       extrn SynchFlag           : word                ; @V2.1XXX01

       extrn HotPlugHandle       : dword
       extrn Device_Help         : dword

       extrn SetupForWait        : near
       extrn IsWaitOver          : near
       extrn HookHotPlugPDI      : far

       extrn  WriteControlRegister : near

       extrn  _RM_MSE_AllocPorts   : far
       extrn  _RM_MSE_AllocPort2   : far
       extrn  _RM_MSE_DeallocPorts : far
       extrn  _RM_MSE_DeallocPort2 : far

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

       public  CheckforPDIDevice
       public  Enable_Ints
       public  ResetMouse
       public  ResetPrescott
       public  WriteInputBuffer
       public  SendToMouse
       public  Read8042Data
       public  GetMouseData
       public  SetSampleRate
       public  SetScaling
       public  SetResolution
       public  EnablePDI
       public  ClearAuxPort
       public  PDIInit
       public  EnableKbdInt
       public  DisableKbdInt
       public  Find3ButtonMouse                      ; @V2.1XXX01
       public  PDIWaitForPW                          ; @V3.0PMS01

;************************************************************************
;*
;*  FUNCTION NAME  :  CheckforPDIDevice
;*
;*  DESCRIPTION    :  This routine firsts issues the Disable Keyboard
;*                    Interface (ADh) to the controller. It then issues
;*                    a Write Controller Ram (60h) command. It writes
;*                    a 54h to the controller where the bits are
;*                    defined below.
;*
;*  We need to disable interrupts for both keyboard and mouse
;*  during this init routine. There are various controller
;*  commands that would cause an IRQ 1. The keyboard DD would
;*  probably think the interrupt was a scan code and get
;*  confused. The mouse does not register its interrupt handler
;*  until the end of the init routine which makes sense. Why
;*  complicate the interrupt handler when the only thing
;*  needed after init time is mouse event handling
;*
;*
;*  ENTRY POINT   : CheckforPDIDevice   LINKAGE:  CALL NEAR
;*
;*  INPUT         :  N/A
;*
;*  RETURN-NORMAL : Carry Flag clear
;*
;*  RETURN-ERROR  :  Carry Flag Set
;*
;*  EFFECTS       :  Changes ES
;*
;*  INTERNAL REFERENCES:
;*     ROUTINES:  None.
;*
;*  EXTERNAL REFERENCES:
;*     ROUTINES:  NONE.
;*     DevHlps:  None.
;*
;*            This routine firsts issues the Disable Keyboard
;*            Interface (ADh) to the controller. It then issues
;*            a Write Controller Ram (60h) command. It writes
;*            a 54h to the controller where the bits are
;*            defined below;
;*
;*************************************************************************

CheckforPDIDevice  proc  near

;*************************************************************************
;* WARNING 10/24/91:
;*
;* It is necessary to first check if POST has found a pointing device
;* plugged into the AUX (PS/2) port. Some clones were responding to the
;* test AUX interface command (0a9h) as if they had a system mouse port
;* when in fact they did not. When the preceeding AUX commands were sent
;* to the controller the 8042 clone chip was leaving the keyboard in a
;* disabled state. The word at 40h:10h is defined as the Equipment flags
;* word. This word can also be retrieved via an Int 11h call. Bit 2 of
;* this word is the Pointing device installed bit. POST will attempt to
;* do a reset (0ffh) command to the AUX device. If the AUX device responds
;* with an 0aah (POR complete) this bit is turned ON. This is supposed to
;* be an industry standard and every system seems to set this bit correctly
;* to date.
;**************************************************************************

       push 40h
       pop  es
       mov  ax, word ptr es:[10h]     ; Equipment flags
       test ax, 4                     ; Bit 2 - Pointing device installed
       jnz  pdi_ok
       cmp  ABIOS_Mch,TRUE            ; ABIOS machines ALWAYS have PDI port
       jz   pdi_ok
       stc
       jmp  pdi_return

pdi_ok:
       mov al, Init_Time
       .if <al ne 0>
          pusha
          push es
          push 60h
          call _RM_MSE_AllocPorts
          pop dx
          or ax, ax
          jnz short PortPDIClaimed
          push 64h
          call _RM_MSE_AllocPort2
          or ax, ax
          pop ax
PortPDIClaimed:
          pop es
          popa
          jnz  pdi_claimed
       .endif

;*****************************************************************************
;* @V3.0PMS01
;* We now check to see if the 8042 is inhibited or waiting for a password to
;* be entered.  The 8042 only interrupts the keyboard after the passoword
;* has been entered so we will have to keep checking using the system timer.
;*****************************************************************************

;*************************** @V3.0PMS01  BEGIN *******************************

        in      al,STATUS_8042        ; Get Controller Status Register

        test    AL,10h                ; Test for BIT4 (Inhibit Switch)
        jnz     pdi_initmse           ; BIT4 is set so we can init mouse now

        mov     ax,OFFSET PDIWaitforPW
        mov     bx,30h                ; Each tick is 32ms, 48 ticks = 1.5 sec
        mov     dl,DevHlp_TickCount   ; Kick off Timer Hook
        call    Device_Help

        jmp     pdi_return            ; All Done Here

pdi_initmse:

;*************************** @V3.0PMS01  END    *******************************

       call DisableKbdInt             ; disable keyboard interrupt

       mov  al, 0adh                  ; Disable the keyboard.
       call WriteControlRegister      ; send command to controller (64h)
       jc   pdi_error

       mov  al, 20h                   ; Tell 8042 that we want to read the
       call WriteControlRegister      ; controller command byte from (60h)
       jc   pdi_error

       call Read8042Data              ; read the controller command byte.
       jc   pdi_error

       and  al, 40h
       mov  TranslateMode, al         ; save keyboard translate mode

       mov  al, 60h                   ; Tell 8042 that we want to write the
       call WriteControlRegister      ; controller command byte from (60h).
       jc  pdi_error


;**************************************************************************
;* The bit definitions for the controller command byte on any system that
;* has an AUX port are listed below;
;*
;*      Bit   Function
;*
;*  0  7 -  Reserved (Always set to 0)
;*  1  6 -  IBM Keyboard Translate Mode
;*  0  5 -  Disable AUX Device  (0 = Enabled state, 1 = disabled state)
;*  1  4 -  Disable Keyboard    (0 = Enabled state, 1 = disabled state)
;*  0  3 -  Reserved (Always set to 0)
;*  1  2 -  System Flag (Always set to 1)
;*  0  1 -  Enable Auxiliary Interrupt (0 = No Aux Ints, 1 = AUX ints enabled)
;*  0  0 -  Enable Keyboard Interrupt  (0 = No Kbd Ints, 1 = Kbd ints enabled)
;*
;* NOTE: I have noticed that this byte is initially set to 65h on systems
;*       with an AUX port and 45h on systems without an AUX port.
;*
;* WARNING!!! On family1 systems without an AUX port the AUX related
;*            bits (1 and 5) should always be set to zero.
;**************************************************************************

       mov  al, 54h                   ; Write the command byte to controller
       call WriteInputBuffer          ; Send it to 8042 port (60h).
       jc  pdi_error

;*
;* We will now issue the 8042 command to test the auxiliary interface.
;* This command only exists on 8042s that support an auxiliary device. If
;* the test succeeds, a 00h will be placed in the 8042's output buffer.
;* If no output appears in the 8042's output buffer, it is assumed that the
;* 8042 does not support an auxiliary device.
;*

;*
;* WARNING: The testing of the auxiliary interface will more than likely
;* screw up an auxiliary device attached to it. Therefore, the auxiliary
;* device should be initialized after calling this procedure.
;*
       mov  al, 0a9h                  ; Command to test the auxiliary
       call WriteControlRegister      ; device.
       jc   pdi_error                 ; Leave if error.

       call Read8042Data              ; Read test results from port (60h)
       jc   pdi_error                 ; No auxiliary device.

;*
;* WARNING - On certain clones I have noticed that we consistantly
;* get back a 01 from the 0xA9 command. This means that the AUX device
;* clock line is stuck low. If we ignore this error and continue on
;* everything works ok. The reset command follows so it is sufficient
;* to say that if we get data back from the 8042 then we have an AUX
;* port. The rest of the code will ensure that a functional pointing
;* device is attached to the system.  (3/4/92)
;*

;***   .if <ZERO al>                  ; Was the byte we got 0?
          mov  AUXPortExists, TRUE    ; It was initialized to FALSE
;**  .else
;**     jmp  pdi_error
;**  .endif

       call IsScrnKeypad              ; is it a screen reader keypad?
       jc   notpres

       call ResetPrescott
notpres:

       call ResetMouse
       jc  pdi_error

       call Find3ButtonMouse          ; @V2.1XXX01

       call SetSampleRate
       jc  pdi_error

       call SetResolution
       jc  pdi_error

       call SetScaling
       jc  pdi_error

       call EnablePDI
       jc  pdi_error

;*
;* Now enable the keyboard and aux interfaces and the aux interrupts.
;*
       mov  bl, 07h                   ; both kbd and aux
       or   bl, TranslateMode
       call Enable_Ints
       .if  <nc>
          mov  DeviceData.IRQ,12      ; set IRQ level (system defined)
          jmp  pdi_exit
       .endif

pdi_error:
       .if <AUXPortExists eq TRUE>
          mov  bl, 25h                ; We have an AUX port
          or   bl, TranslateMode
          call Enable_Ints
          mov  al, 0a7h               ; Disable Auxilary Device Interface
          call WriteControlRegister
          call ClearAuxPort           ; clear the aux port
       .else
          mov  bl, 05h                ; No AUX port, bits are slightly different
          or   bl, TranslateMode
          call Enable_Ints
       .endif

       mov al, Init_Time
       .if <al ne 0>
          pusha
          push es
          call _RM_MSE_DeallocPorts
          call _RM_MSE_DeallocPort2
          pop es
          popa
       .endif

pdi_claimed:
       stc

pdi_exit:
       call EnableKbdInt              ; enable keyboard interrupt
pdi_return:
       ret

CheckforPDIDevice  endp


;****************************************************************
;*
;*  FUNCTION NAME  :  Enable_Ints
;*
;*  DESCRIPTION    :  Enable keyboard interface
;*
;*                    This routine firsts issues an Enable Keyboard
;*                    Interface (AEh) to the controller. It then issues
;*                    a Write Controller Ram (60h) command. It writes
;*                    the caller's value to the controller RAM.
;*
;*  ENTRY POINT   :  Enable_Ints       LINKAGE:  CALL NEAR
;*
;*  INPUT         :  BL = value to write to controller RAM
;*
;*  RETURN-NORMAL :  Keyboard enabled and IRQ 1 activated.
;*
;*  RETURN-ERROR  :  N/A.
;*
;*  EFFECTS       :  None
;*
;*
;****************************************************************

Enable_Ints  proc  near

        mov  al, 0aeh                  ; Enable the keyboard.
        call WriteControlRegister      ; send command to controller (64h)
        jc   ei_exit

        mov  al, 60h                   ; Tell 8042 that we want to write the
        call WriteControlRegister      ; command byte.
        jc   ei_exit                   ; Leave if we have an error.

        mov  al, bl                    ; Write callers value
        call WriteInputBuffer          ; Send it to 8042.

ei_exit:
        ret

Enable_Ints  endp


;****************************************************************
;*
;*  FUNCTION NAME :  ResetMouse
;*
;*  DESCRIPTION   : This procedure attempts to reset a PS/2
;*                    mouse. It does this by sending a reset
;*                    command to the mouse and checking to
;*                    ensure that it passed its diagnostics.
;*
;*   INPUT        :  Mouse interrupts disabled.
;*
;*   OUTPUT       :   Carry clear     Mouse has been reset correctly
;*                     AL              ID Code
;*
;*   RETURN-ERROR :  Carry set  Error condition.
;*
;*   ALTERS       : AX, CX
;*
;*   CALLS        : SendToMouse, GetMouseData
;*
;****************************************************************

ResetMouse  proc  near

        mov   al, 0ffh                ; Send the reset command to the mouse.
        call  SendToMouse
        jc   rm_exit
        call GetMouseData             ; Get response from the mouse
        .if <al ne 0fah>
           stc
           jmp  rm_exit
        .endif

        call GetMouseData             ; Get response from the mouse
        .if <al ne 0aah>
           stc
           jmp  rm_exit
        .endif

        call GetMouseData             ; Get response from the mouse
        .if <ZERO al>
           clc
        .else
           stc
        .endif

rm_exit:
        ret

ResetMouse  endp


;****************************************************************
;*
;*  FUNCTION NAME :  IsScrnKeypad
;*
;*  DESCRIPTION   :  This procedure attempts to determine
;*                   if a ScreenReader 18-key keypad is
;*                   plugged into the PDI port
;*
;*  INPUT         :  This routine must be called after the 8042 has
;*                   been put in disable mode.
;*
;*  OUTPUT        :  Carry clear     No keypad attached
;*                   Carry set       Keypad attached
;*
;****************************************************************

IsScrnKeypad proc  near
        mov   al, 0f2h                ; Read the device type attached
        call  SendToMouse
        jc   ik_exit

        call GetMouseData             ; Get response (should be ACK x'FA')
        cmp  al,0FAh
        jne  ik_exit

        call GetMouseData             ; Get ID (should be x'01' for pad)
        cmp  al,01
        jne  ik_exit
        mov  ScreenKeypad,TRUE
        stc
        ret
ik_exit:
        clc
        ret

IsScrnKeypad endp


;****************************************************************
;*
;*  FUNCTION NAME  : ResetPrescott
;*
;*  DESCRIPTION    : This procedure attempts to reset a
;*                    Prescott display by sending a reset
;*                    command to the device and checking to
;*                    ensure that it passed its diagnostics.
;*
;*   INPUT         : Mouse interrupts disabled.
;*
;*   OUTPUT        : Carry clear     Mouse has been reset correctly
;*                     AL              ID Code
;*
;*   EXIT ERROR    : Carry set  Error condition.
;*
;*   ALTERS        : AX, CX
;*
;*   CALLS         : SendToMouse, GetMouseData
;*
;****************************************************************

ResetPrescott proc  near

        mov   al, 0bbh                ; Send the reset command to the
        call  SendToMouse             ; 8516 Touch Display
        jc   rp_exit

        call GetMouseData             ; Get response from the 8516 display
        .if <al ne 0cah>
           stc
           jmp  rp_exit
        .endif

        mov  dx, 99
rp_loop:
        mov  cx, 100                  ; Wait for 100 millisecs
        call SetupForWait
        .repeat
           call IsWaitOver
        .until <c>

        in   al, 64h                 ; Get current 8042 status.
        and  al, 21h                 ; We're only interested in Aux OBF bits
        cmp  al, 21h                 ; If OBF and Aux data then
        jz   rp_data                 ; It's OK to proceed
        dec  dx
        jnz  rp_loop
        stc
        jmp  rp_exit

rp_data:                             ; There is mouse data to be read.

        in   al, 60h                 ; Read byte of data from Prescott
        mov  bl, al
        in   al, 64h
        test al, 0c0h                ; Parity Error + General Time-Out bits
        jnz  rp_loop                 ; should be off

        .if <bl ne 0abh> AND
        .if <bl ne 0cdh>
           stc
           jmp  rp_exit
        .endif

        call GetMouseData             ; Get response from the mouse
        .if <al eq 2>
           mov  PrescottDsp, TRUE
           clc
        .else
           stc
        .endif

rp_exit:
        ret

ResetPrescott  endp


;****************************************************************
;*
;*  FUNCTION NAME :  WriteInputBuffer
;*
;*  DESCRIPTION   : This procedure will send a byte of data to the
;*                  8042 (port 60h).
;*
;*  NOTES         : Before the data is sent to the 8042 both the input
;*                  buffer full and output buffer full bits of the status
;*                  register must be off.
;*
;*               This procedure sends a byte of data to the 8042's
;*               input buffer. It should not be called unless the
;*               8042 has already been set up to expect this byte of data.
;*
;*               Only 64K attempts will be made before timing out.
;*
;*   INPUT        : AL - Data byte to be sent.
;*
;*   OUTPUT       : Carry clear - Data sent sucessfully
;*                  Carry set   - Data not sent, error condition.
;*
;*   ALTERS       : CX register
;*
;****************************************************************

WriteInputBuffer  proc  near

;*
;* Upon entry, it is assumed that a command has just been sent to the
;*  8042. Therefore, we will wait until the 8042 has removed the command
;*  byte from its input buffer before doing anything else.
;*

        push ax                      ; Save callers value to be written
        xor  cx, cx                  ; Loop counter

wib_retry:
        in   al, 64h                 ; Get 8042's current status.
        test al, 03h                 ; Is the in/out buffer still full?
        jz   wib_ok                  ; It's OK to proceed
        loop wib_retry               ; Try again.
        stc                          ; Error condition
        pop  ax                      ; Callers value on top of stack
        jmp  short wib_exit          ; Return with failure.

wib_ok:                              ; Input and output buffers are empty.
        pop  ax                      ; Get saved data byte.
        out  60h, al                 ; Send data byte.
        clc                          ; Show success.

wib_exit:
        ret

WriteInputBuffer  endp


;****************************************************************
;*
;*  FUNCTION NAME : SendToMouse
;*
;*  DESCRIPTION   : This procedure will send a command to the
;*                  auxiliary device
;*
;*  NOTES         : The routine first sends a Write to Auxiliary Device
;*                  (D4h) command to the controller. It then sends the
;*                  callers command which was passed in (AL register)
;*                  to port 60h which is the Aux device at this time.
;*
;*   INPUT        :  AL - Command to be sent.
;*
;*   OUTPUT       :  Carry clear - Command sent sucessfully
;*                   Carry set   - Command not sent, error condition.
;*
;****************************************************************

SendToMouse  proc  near

        push ax                      ; Save command/data byte.
        mov  al, 0d4h                ; Tell 8042 we want to send a byte to
        call WriteControlRegister    ; the auxiliary device.
        pop  ax                      ; Get saved command/data byte.
        jc   stm_exit                ; Leave if error.
        call WriteInputBuffer        ; Send data/command to aux dev.
stm_exit:
        ret

SendToMouse  endp


;****************************************************************
;*
;*  FUNCTION NAME  :  Read8042Data
;*
;*  DESCRIPTION    : This procedure will wait until there is data
;*                   in the output buffer and return it in AL.
;*
;*  NOTE: Before the data is read the output buffer full bit
;*        must be on in the 8042 Controller Status Register.
;*
;*        Only 64K attempts will be made before timing out.
;*
;*  INPUT         : N/A
;*
;*  OUTPUT        :  Carry clear - AL holds the data byte
;*                   Carry set   - Error condition.
;*
;****************************************************************

Read8042Data  Proc  Near

        xor  cx,cx

rd_retry:
        in   al, 64h              ; Read status port of 8042
        test al, 01h              ; Is the output buffer full
        jnz  rd_ok                ; If so, it's OK to proceed
        loop rd_retry             ; try again
        stc                       ; Error condition
        jmp  rd_exit

rd_ok:
        in  al, 60h               ; get data
        clc                       ; clear carry for no error

rd_exit:
        ret

Read8042Data  endp


;****************************************************************
;*
;*  FUNCTION NAME :  GetMouseData
;*
;*  DESCRIPTION   : This procedure will try to read a byte of
;*                  data from the auxiliary device.
;*
;*  NOTE: Only 15*64K attempts will be made before timing out.
;*
;*        I have seen instances where 64K times is not
;*        enough time for the AUX output buffer full bit to
;*        turn on. This happened on the reset mouse command.
;*        It seems that 15*64K is enough for all systems to
;*        date. (WARNING - 8/15/90)
;*
;*   INPUT        :  N/A
;*
;*   OUTPUT       : Carry clear     Read was successfully
;*                  AL              The byte of data that was read
;*
;*                  Carry set       The byte of data could not be read
;*
;*   ALTERS       : CX and AX registers
;****************************************************************

GetMouseData  Proc  Near


        mov  ah, 15                  ; Outer loop counter is 15
gmd_outer:
        xor  cx,cx                   ; Inner loop counter is 64K
gmd_inner:
        in   al, 64h                 ; Get current 8042 status.
        and  al, 21h                 ; We're only interested in Aux OBF bits
        cmp  al, 21h                 ; If OBF and Aux data then
        jz   gmd_ok                  ; It's OK to proceed
        loop gmd_inner               ; Keep trying the desired number of
        dec  ah
        jnz  gmd_outer
        xor  al,al
        stc
        jmp  gmd_exit

gmd_ok:                              ; There is mouse data to be read.
        in   al, 60h                 ; Read byte of data from mouse.
        clc

gmd_exit:
        ret

GetMouseData  endp


;****************************************************************
;*
;*  FUNCTION NAME  :  SetSampleRate
;*
;*  DESCRIPTION    :  Send the SetSampleRate Command (0f3h)
;*                     to the Aux device.
;*
;*  NOTES: The sample rate was previously set to 100 reports
;*         per second by the Reset command. We will set it to
;*         60 reports per second.
;*
;*  ENTRY POINT   :          LINKAGE:  CALL NEAR
;*
;*  INPUT         :  N/A
;*
;*  RETURN-NORMAL :  Carry Flag clear.
;*
;*  RETURN-ERROR  :  Carry Flag set.
;*
;*
;****************************************************************

SetSampleRate  proc  near

       mov  al, 0f3h          ; set sample rate command
       call SendToMouse       ; send command to mouse
       jc   ssr_exit

       call GetMouseData      ; wait for response
       .if <c> or
       .if <al ne 0fah>
           stc
          jmp  ssr_exit
       .endif

       mov  al, PDI_SAMPLERATE ; sample rate of 60/sec (was 40/sec)
       call SendToMouse       ; send command to mouse
       jc   ssr_exit

       call GetMouseData
       .if <c> or
       .if <al ne 0fah>
          stc
          jmp  ssr_exit
       .endif

ssr_exit:
       ret

SetSampleRate endp

;****************************************************************
;*
;*  FUNCTION NAME :  SetScaling
;*
;*  DESCRIPTION   :  Send the SetScaling 2:1 Command (0E7h)
;*
;*  NOTES         : The scaling rate was previously set to 1:1
;*
;*
;*  INPUT         :  N/A
;*
;*  RETURN-NORMAL :  Carry Flag clear.
;*
;*  RETURN-ERROR  :  Carry Flag set.
;*
;*
;****************************************************************

SetScaling  proc  near

       mov  al, 0e7h          ; set sample rate command
       call SendToMouse       ; send command to mouse

       call GetMouseData      ; wait for response
       .if <c> or
       .if <al ne 0fah>
           stc
       .endif

       ret

SetScaling endp

;****************************************************************
;*
;*  FUNCTION NAME :  SetResolution
;*
;*  DESCRIPTION   :  Send the SetResolution Command (0e8h)
;*                     to the Aux device.
;*
;*  NOTES: The resolution was previously set to 4 counts per mm
;*         (100 ppi) by the Reset command. We use this call
;*         to set the resolution to 8 counts per mm or 200ppi.
;*
;*  INPUT         :  N/A
;*
;*  RETURN-NORMAL :  Carry Flag clear.
;*
;*  RETURN-ERROR  :  Carry Flag set.
;*
;*
;****************************************************************

SetResolution  proc  near

          mov  al, 0e8h          ; set resolution
          call SendToMouse       ; send command to mouse
          jc   sr_exit           ; error, exit init bad

          call GetMouseData
          .if <c> or
          .if <al ne 0fah>
             stc
             jmp  sr_exit
          .endif

          mov  al, PDI_RESOLUTION ; resolution of 8 counts/mm
          call SendToMouse       ; send command to mouse
          jc   sr_exit           ; error, exit init bad

          call GetMouseData
          .if <al ne 0fah>
             stc
          .else
             mov  DeviceData.NumMics, 80  ; 80 mickeys/cm
          .endif
sr_exit:
          ret

SetResolution  endp

;****************************************************************
;*
;*  FUNCTION NAME  :  EnablePDI
;*
;*  DESCRIPTION    :  Enable the Aux Device.
;*
;*                   This routine sends the Enable command (0f4h) to
;*                   the auxiliary device.
;*
;*  INPUT         :  N/A
;*
;*  RETURN-NORMAL :  Carry Flag clear.
;*
;*  RETURN-ERROR  :  Carry Flag set.
;*
;*
;****************************************************************

EnablePDI  proc  near

       mov  al, 0f4h          ; enable pointing device
       call SendToMouse       ; send command to mouse
       .if <nc>
          call GetMouseData      ; wait for response
          .if <al ne 0fah>
             stc
          .endif
       .endif
       ret

EnablePDI  endp


;****************************************************************
;*
;*  FUNCTION NAME :  ClearAuxPort
;*
;*  DESCRIPTION   : This procedure will read all the aux port data
;*                  until the controller status register's bits
;*                  indicate that there is no more aux data to
;*                  be read.
;*
;*  NOTE: This routine will only exit when the Output Buffer
;*        Full and Auxiliary Output Full bits are OFF in the
;*        controller status register (port 64h).
;****************************************************************

ClearAuxPort  Proc  Near

       in   al, 64h              ; read status port of 8042
       and  al, 21h              ; get AOBF and OBF bits only

       .while <al eq 21h>        ; While AUX data is in output buffer
          in   al, 60h           ; read aux data
          MyIODelay              ; Generate delay between I/O instructions
          in   al, 64h           ; read status port of 8042
          and  al, 21h           ; get AOBF and OBF bits only
       .endwhile

       ret

ClearAuxPort  EndP


;****************************************************************
;*
;*  FUNCTION NAME  :  PDIInit
;*
;*  DESCRIPTION    :  Gets the PDI LID if on ABIOS system
;*
;*                   This routine will check to see if we are on an
;*                   ABIOS system. If so, it will obtain the LID for
;*                   the PDP device.
;*
;*  NOTE          :  This routine is only called if we have detected
;*                   a PDP device.
;*
;*  ENTRY POINT   :  PDIInit           LINKAGE:  CALL NEAR
;*
;*  INPUT         :  DS = Base data selector
;*
;*  RETURN-NORMAL :  Always, mouse LID obtained
;*
;*  RETURN-ERROR  :  N/A.
;*
;*  EFFECTS       : Stack is clean on return.  AX, CX, DX, SI, and DI
;*                  registers are changed.
;****************************************************************

PDIInit  proc  near

       .if <ABIOS_Mch eq TRUE>
          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
       .endif

       lea   eax, HookHotPlugPDI            ; 16 bit offset to Hot Plug handler
       mov   ebx, 0FFFFFFFFh                ; RESERVED
       mov   dl, DevHlp_AllocateCtxHook
       call  Device_Help

       .if <nc>
          mov   HotPlugHandle,  eax
       .endif

        ret

PDIInit  endp

KBD_INT_MASK    equ     02h

EnableKbdInt    proc near
        pushf
        cli
        push    ax

; #81365 WHH start

ifndef SMP
        in      al, 21h              ; read current status
        and     al, not KBD_INT_MASK ; unmask KBD
        out     21h, al              ; out new value
        MyIODelay
else
        push    dx
        mov     dl, DevHlp_SetIRQMask
        mov     al, 1     ; keyboard IRQ = 1
        mov     ah, 0     ; 0 = enable
        call    Device_Help
        pop     dx
endif

; #81365 WHH end

        pop     ax
        sti
        popf
        ret
EnableKbdInt    endp

DisableKbdInt   proc near
        pushf
        cli
        push    ax

; #81365 WHH start

ifndef SMP
        in      al, 21h              ; read current status
        or      al, KBD_INT_MASK     ; mask KBD
        out     21h, al              ; out new value
        MyIODelay
else
        push    dx
        mov     dl, DevHlp_SetIRQMask
        mov     al, 1     ; keyboard IRQ = 1
        mov     ah, 1     ; 1 = disable
        call    Device_Help
        pop     dx
endif

; #81365 WHH end

        pop     ax
        sti
        popf
        ret
DisableKbdInt   endp

;*********************************************************************
;*
;*  FUNCTION NAME :  Find3ButtonMouse                ; @V2.1XXX01
;*
;*  DESCRIPTION   :  Send the SetResolution Command (0e8h), 1 count/mm
;*                   to the Aux device followed by three SetScaling
;*                   Commands (0e6h).  This is followed by a read of the
;*                   status register.
;*
;*  NOTES: The algorithym was supplied by Logitech for detecting and
;*         supporting their three button mice on the PDI port.
;*
;*  INPUT         :  N/A
;*
;*  RETURN-NORMAL :  Carry Flag clear.   DeviceData.NumButt updated.
;*
;*  RETURN-ERROR  :  Carry Flag set.
;*
;*
;****************************************************************

Find3ButtonMouse proc  near

       mov  al, 0e8h                 ; set resolution
       call SendToMouse              ; send command to mouse
       jc   fb_exit                  ; error, exit init bad

       call GetMouseData             ; verify set resolution worked
       .if <c> or
       .if <al ne 0fah>
          stc
          jmp  fb_exit
       .endif

       mov  al, 00h                  ; set resolution to 1 count per mm
       call SendToMouse              ; send command to mouse
       jc   fb_exit                  ; error, exit init bad

       call GetMouseData             ; verify set resolution worked again
       .if <al ne 0fah>
          stc
       .else

          mov  al, 0e6h              ; set scaling = 1:1
          call SendToMouse           ; send command to mouse
          jc   fb_exit

          call GetMouseData          ; verify set scaling worked
          jc   fb_exit
          cmp  al, 0fah
          jnz  fb_exit

          mov  al, 0e6h              ; set scaling = 1:1
          call SendToMouse           ; send command to mouse
          jc   fb_exit

          call GetMouseData          ; verify set scaling worked
          jc   fb_exit
          cmp  al, 0fah
          jnz  fb_exit

          mov  al, 0e6h              ; set scaling = 1:1
          call SendToMouse           ; send command to mouse
          jc   fb_exit

          call GetMouseData          ; verify set scaling worked
          jc   fb_exit
          cmp  al, 0fah
          jnz  fb_exit

          mov  al, 0e9h              ; status request (will generate 3 bytes)
          call SendToMouse           ; send command to mouse
          jc   fb_exit
                                     ; We must clear all three bytes from data
                                     ; port.

          call GetMouseData          ; Verify status request worked
          jc   fb_exit
          cmp  al, 0fah
          jnz  fb_exit

          call GetMouseData          ; Throw away Standard status info
          jc   fb_exit               ; BYTE 1

          call GetMouseData          ; Logitech Number of mouse buttons
          jc   fb_exit               ; BYTE 2

          .if <al eq 3>              ; Three buttons reported?
             mov DeviceData.NumButt, al
          .endif

          call GetMouseData          ; Throw away firmware revision number
                                     ; BYTE 3
       .endif

fb_exit:
        clc                          ; Never return an error
        ret


Find3ButtonMouse endp

;*****************************************************************************
;*
;*  FUNCTION NAME  :  PDIWaitForPW                                  @V3.0PMS01
;*
;*
;*  DESCRIPTION    : Waits for the Inhibit bit to be set on the 8042
;*                   controller so the mouse can be initialize.  This code
;*                   was added to support unattended (or server) boot
;*                   operation.  The polling is not the most efficient but
;*                   only the keyboard gets interrupted when the power on
;*                   password is entered.  What should be implemented is
;*                   a call back from the keyboard driver to the mouse to
;*                   notify the mouse that the 8042 is "unlocked".
;*
;*  NOTE          :  This routine is only called as long as the 8042 is
;*                   waiting for a password to be entered.  The HotPlugHandle
;*                   will get set by the PDIINIT routine but we need to
;*                   account for the fact that the user could enter the
;*                   password before we have allocated the routine.  Once
;*                   we have armed the context hook for "HotPlug", we will
;*                   remove ourself from the timer.
;*
;*
;*  ENTRY POINT   :  PDIWaitForPW           LINKAGE:  CALL FAR
;*
;*  INPUT         :  DS = Base data selector
;*
;*  RETURN-NORMAL :  Always, Timer hook set if waiting for password
;*                   otherwise HotPlug context hooked is armed.
;*
;*  RETURN-ERROR  :  N/A.
;*
;*  EFFECTS       : Stack is clean on return.  All registers are returned
;*                  unmodified.
;*****************************************************************************

PDIWaitForPW proc  far              ; BEGIN @V3.0PMS01

        pushf                       ; Save Flags (requirement for TIMERS)

        push    eax                 ; Save EAX
        push    ebx                 ; Save EBX
        push    ecx                 ; save ECX
        push    edx                 ; Save EDX

        in      al,STATUS_8042      ; Get Controller Status Register

        test    AL,10h              ; Test for BIT4 (Inhibit Switch)
        jz      PW_EXIT             ; BIT4 is CLEAR so we check again later


        cmp     HotPlugHandle,0     ; Check if Handle has been allocated yet
        je      PW_EXIT             ; otherwise we will wait again.
        mov     eax, 0
        mov     ebx, HotPlugHandle
        mov     ecx, 0FFFFFFFFh
        mov     dl,  DevHlp_ArmCtxHook
        call    Device_help         ; BUGBUG - Not going to worry about CY flag
                                    ;          since it should NEVER be set


        mov     ax,OFFSET PDIWaitforPW  ; Remove TIMER
        mov     dl,DevHlp_ResetTimer
        call    Device_Help         ; BUGBUG - Not going to worry about CY flag
                                    ;          since it should NEVER be set


PW_EXIT:
        pop     edx                 ; Restore EDX
        pop     ecx                 ; Restore ECX
        pop     ebx                 ; Restore EBX
        pop     eax                 ; Restore EAX

        popf                        ; Restore FLAGS Register
        ret                         ; Return back to calling routine

PDIWaitForPW endp                   ; END @V3.0PMS01

CSEG     ENDS
         END
