; Copyright 1996 Acorn Computers Ltd
;
; Licensed under the Apache License, Version 2.0 (the "License");
; you may not use this file except in compliance with the License.
; You may obtain a copy of the License at
;
;     http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing, software
; distributed under the License is distributed on an "AS IS" BASIS,
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; See the License for the specific language governing permissions and
; limitations under the License.
;
; > KbdResPC

; This file contains the minimal PC keyboard control stuff that the kernel does on reset.
; The only two hooks in this file used externally are IRQ_Test_CTRL_or_R_Pressed
; and SetUpKbd.

; For now, use development podule in slot 0.
IOBase          *       IOMD_Base
IOData          *       IOCSERTX
IOStatus        *       IOMD_KBDCR
IOControl       *       IOMD_KBDCR
stat_RXF        *       IOMD_KBDCR_RxF
stat_TXE        *       IOMD_KBDCR_TxE
ctl_Enable      *       IOMD_KBDCR_Enable
ctl_EnableIRQ   *       0       ; not needed on IOMD


; PC keyboard codes we are interested in.
PCReset         *       &AA
PCSpecial       *       &E0
PCCTRLL         *       &14
PCCTRLR         *       &14     ; Preceded by &E0
PCSHIFTL        *       &12
PCSHIFTR        *       &59
PCR             *       &2D
PCT             *       &2C
PCDelete        *       &71     ; Preceded by &E0
PCBSpace        *       &66
PCEnd           *       &69     ; Preceded by &E0

KeyData
        DCB     PCCTRLL,  CTRL_Down_Flag
        DCB     PCSHIFTL, SHIFT_Down_Flag
        DCB     PCSHIFTR, SHIFT_Down_Flag
        DCB     PCR,      R_Down_Flag
        DCB     PCT,      T_Down_Flag
        DCB     PCBSpace, Del_Down_Flag
        DCB     0
        ALIGN

SpecialData
        DCB     PCCTRLR,  CTRL_Down_Flag
        DCB     PCDelete, Del_Down_Flag
        DCB     PCEnd,    Copy_Down_Flag
        DCB     0
        ALIGN

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

  [ :LNOT HAL

SetUpKbd
        MOV     r0, #IOBase
        MOV     r1, #ctl_Enable + ctl_EnableIRQ
        STRB    r1, [r0, #IOControl]
10
        LDRB    r1, [r0, #IOStatus]
        TST     r1, #stat_TXE
        MOVNE   r1, #&FF
        STRNEB  r1, [r0, #IOData]
        BEQ     %BT10

 [ MorrisSupport
  [ {TRUE} ; ARM7500FE support
; Change test to check for IOMD_Original, rather than IOMD_7500, so we include IOMD_7500FE
; in the latter category

        LDRB    r1, [r0, #IOMD_ID0]
        LDRB    r2, [r0, #IOMD_ID1]             ; safe to use r2, since SetUpKbdReturn corrupts it
        ORR     r1, r1, r2, LSL #8              ; straight away
        LDR     r2, =IOMD_Original
        TEQ     r1, r2
        BEQ     %FT30
  |
        LDRB    R1, [R0, #IOMD_ID0]             ;Are we running on Morris
        CMP     R1, #&E7
        LDRB    R1, [R0, #IOMD_ID1]
        CMPEQ   R1, #&5B
        BNE     %FT30                           ;NE: no, assume IOMD, so only one PS2 port
  ]

        MOV     R1, #IOMD_MSECR_Enable          ;yes, so initialise 2nd PS2 (mouse) port cos
        STRB    R1, [R0, #IOMD_MSECR]           ;keyboard may be connected there instead
20
        LDRB    R1, [R0, #IOMD_MSECR]
        TST     R1, #IOMD_MSECR_TxE             ;Is port ready to accept data
        MOVNE   R1, #&FF                        ;NE: port ready, so send 'reset' command
        STRNEB  R1, [R0, #IOMD_MSEDAT]          ;
        BEQ     %BT20                           ;EQ: loop til port ready

        MOV     R1, #IOMD_MouseRxFull_IRQ_bit
        STRB    R1, [R0, #IOMD_IRQMSKD]

        MOV     R0, #InitKbdWs
        MOV     R1, #2
        STRB    R1, [R0, #Port2Present]
30
 ]
        MOV     r0, #InitKbdWs
        ADR     r1, KeyData
        STR     r1, [r0, #KeyDataPtr]

        B       SetUpKbdReturn

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

; On ARM600, this routine must work in IRQ32 mode

IRQ_Test_CTRL_or_R_Pressed ROUT
        SUB     lr, lr, #4
        Push    "r0-r2,lr"

        MOV     r2, #IOBase
 [ MorrisSupport
        MOV     lr, #InitIRQWs
        LDRB    r1, [lr, #Port2Present] ;Check if 2nd PS2 port (in Morris) is available
        TEQ     r1, #0

        LDRNEB  r0, [r2, #IOMD_MSECR]   ;NE: yes, so check if interrupt is from it
        TSTNE   r0, #IOMD_MSECR_RxF     ;
        LDRNEB  r2, [r2, #IOMD_MSEDAT]  ;NE: 2nd port present and interrupting, get scan code
        MOVNE   r1, #2                  ;NE: indicate which port
        BNE     %FT5                    ;NE: process it
                                        ;EQ: 2nd port not present or interrupting
                                        ;    drop through and check 1st port
 ]
        LDRB    r0, [r2, #IOStatus]
        TST     r0, #stat_RXF           ; If not keyboard then
        Pull    "r0-r2,pc",EQ,^         ;   exit.

        LDRB    r2, [r2, #IOData]       ; Get scan code.

 [ MorrisSupport
        MOV     r1, #1
5
        LDRB    r0, [lr, #KB_There_Flag]

        TEQ     r2, #0                  ;Assume that zero is the end of a mouse AA 00 start up
        BICEQ   r0, r0, r1              ; sequence, so clear keyboard present indication.
        STREQB  r0, [lr, #KB_There_Flag]
        Pull    "r0-r2,pc",EQ,^         ; and exit

        ORRNE   r0, r0, r1              ;Not zero, mark keyboard present
 ]

        MOV     lr, #InitIRQWs

        STRB    r0, [lr, #KB_There_Flag]        ; Keyboard must be there (r0<>0 from above).

        ADR     r1, SpecialData

        TEQ     r2, #PCSpecial          ; If special code then
        STREQ   r1, [lr, #KeyDataPtr]   ;   switch tables
        Pull    "r0-r2,pc",EQ,^         ;   and exit.

        LDR     r0, [lr, #KeyDataPtr]   ; Get pointer to current table.

        TEQ     r0, r1                  ; Only use special table once, then
        ADREQ   r1, KeyData             ;   switch back to normal table.
        STREQ   r1, [lr, #KeyDataPtr]
10
        LDRB    r1, [r0], #2            ; Get key code from table.
        TEQ     r1, #0                  ; If at end of table then
        Pull    "r0-r2,pc",EQ,^         ;   ignore key.

        TEQ     r1, r2                  ; If not this key then
        BNE     %BT10                   ;   try the next.

        LDRB    r1, [r0, #-1]           ; Get flag.
        STRB    r1, [lr, r1]            ; Non-zero means pressed.

        Pull    "r0-r2,pc",,^

  ] ; :LNOT: HAL

        END