; 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.
;
; > KbdResA1

; This file contains all the old-style 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.

                   GBLL   KeyboardDebungling
KeyboardDebungling SETL   {FALSE}

; reset code needs to know where CTRL, SHIFT and R are in the kbd matrix
; these are codes given by the keyboard

     [ Keyboard_Type = "A1A500"
A1CtrlLeft      * &3B
A1CtrlRight     * &61
A1ShiftLeft     * &4C
A1ShiftRight    * &58
A1CTRLLCol   *  K1kdda + (A1CtrlLeft :AND: 15)
A1CTRLLRow   *  K1kdda + (A1CtrlLeft :SHR: 4)
A1CTRLRCol   *  K1kdda + (A1CtrlRight :AND: 15)
A1CTRLRRow   *  K1kdda + (A1CtrlRight :SHR: 4)
A1SHIFTLCol  *  K1kdda + (A1ShiftLeft :AND: 15)
A1SHIFTLRow  *  K1kdda + (A1ShiftLeft :SHR: 4)
A1SHIFTRCol  *  K1kdda + (A1ShiftRight :AND: 15)
A1SHIFTRRow  *  K1kdda + (A1ShiftRight :SHR: 4)
A1R_Col      *  K1kdda +  10
A1R_Row      *  K1kdda +  2
A1T_Col      *  K1kdda +  11
A1T_Row      *  K1kdda +  2
A1Del_Col    *  K1kdda +  4
A1Del_Row    *  K1kdda +  3
A1Copy_Col   *  K1kdda +  5
A1Copy_Row   *  K1kdda +  3
     ]

     [ Keyboard_Type = "A1A500"
; old (A500) keyboard positions

A500CTRLRow    *   KEYDOWN + &C
A500CTRLCol    *   KEYDOWN +  0
A500SHIFTRow   *   KEYDOWN + &A
A500SHIFTCol   *   KEYDOWN +  0
A500R_Row      *   KEYDOWN +  2
A500R_Col      *   KEYDOWN +  7
A500T_Row      *   KEYDOWN +  2
A500T_Col      *   KEYDOWN +  6
A500Del_Row    *   KEYDOWN +  5
A500Del_Col    *   KEYDOWN +  7
A500Copy_Row   *   KEYDOWN +  0
A500Copy_Col   *   KEYDOWN +  8
    ]

; On ARM600, this routine must work in IRQ32 mode

IRQ_Test_CTRL_or_R_Pressed ROUT
        Push    "r0-r2, R10-R12, lr"

        MOV     R12, #IOC

        MOV     r2, #IOC
        MOV     r0, #32
        BL      DoMicroDelay    ; quick thumb twiddle until it's REALLY there
        LDRB    R11, KARTRx     ; read byte transmitted by keyboard

     [ KeyboardDebungling
   Push  R12
   MOV   R12, R11, LSR #4
   TubeChar  R10, R11, "MOV R11, #""R"""
   TubeChar  R10, R11, "ADD R11, R12, #""0"""
   AND   R12, R11, #&F
   TubeChar  R10, R11, "ADD R11, R12, #""0"""
   Pull  R12
     ]

        CMP     R11, #HRDRESET  ; first check for part of reset sequence and reply accordingly

        BEQ     fartaboutfornewkbd

        CMP     R11, #RST1ACK
        MOVEQ   R10, #RST2ACK
        BEQ     send_ack_byte

        CMP     R11, #RST2ACK
        BNE     keytransmission

        MOV     R10, #InitKbdWs
        LDR     R10, [R10, #KeyDataPtr]
        CMP     R10, #0
        MOVNE   R10, #ACK+SCAN
        BNE     send_ack_byte
        MOV     R10, #ACK

  [ KeyboardDebungling
   Push  R12
   MOV   R12, R10, LSR #4
   TubeChar  R10, R11, "MOV R11, #""k"""
   TubeChar  R10, R11, "ADD R11, R12, #""0"""
   AND   R12, R10, #&F
   TubeChar  R10, R11, "ADD R11, R12, #""0"""
   Pull  R12
 ]

        STRB    R10, KARTTx
        BL      PollTxBit
        MOV     R11, #K1rqid
        BL      SendAndPollRxBit

  [ Keyboard_Type = "A1A500"
        AND     r10, r11, #&F0
        CMP     R11, #IDTYPE            ; a500 kbd?
        ADREQ   R10, DataA500Kbd
        BEQ     gotkbdid
  ]
        SUB     r11, r11, #K1kbid + 1
        CMP     r11, #30
        ADRLSL  R10, DataA1Kbd          ; only accept ID 1-31
        MOVHI   R10, #0                 ; else don't know

gotkbdid
        MOV     R11, #InitKbdWs
        STR     R10, [R11, #KeyDataPtr]
 [ Keyboard_Type = "A1A500"
 ASSERT (DataA1Kbd :AND: 255) <> 0
 ]
 [ Keyboard_Type = "A1A500"
 ASSERT (DataA500Kbd :AND: 255) <> 0
 ]
        STRB    R10, [R11, #KB_There_Flag]
                                        ; only there once ID understood
        MOV     R10, #HRDRESET          ; and from the top
        B       send_ack_byte

keytransmission
; assume it's key info
        MOV     R10, #InitKbdWs
        LDRB    R10, [R10]      ; the "had a byte" flag
        CMP     R10, #0
        BNE     hadabyteofkey
        MOV     R10, #InitKbdWs
        STRB    R11, [R10]      ; first part of 2 byte protocol: set flag
        MOV     R10, #ACK+&F
        B       send_ack_byte

fartaboutfornewkbd

kickitagain
        MOV     R11, #HRDRESET
        BL      SendAndPollRxBit        ; get a byte to R11
        BL      PollTxBit
        CMP     R11, #HRDRESET
        BNE     kickitagain
        MOV     R11, #RST1ACK
        BL      SendAndPollRxBit        ; get a byte to R11
        BL      PollTxBit
        CMP     R11, #RST1ACK
        BNE     kickitagain
        MOV     R10, #RST2ACK
        B       send_ack_byte

hadabyteofkey
; now got 1st byte in R10, second byte in R11 : test for CTRL or R
        MOV     R0, #InitKbdWs
        LDR     R0, [R0, #KeyDataPtr]
10      LDRB    R1, [R0], #1
        CMP     R1, #0
        BEQ     %FT11
        CMP     R1, R10
        LDRB    R1, [R0], #1
        CMPEQ   R1, R11
        LDRB    R1, [R0], #1
        BNE     %BT10
        MOV     R11, #InitKbdWs
        STRB    R1, [R11, R1]           ; non-zero means pressed
11
        MOV     R10, #ACK+SCAN
send_ack_byte

     [ KeyboardDebungling
   Push  R12
   MOV   R12, R10, LSR #4
   TubeChar  R10, R11, "MOV R11, #""T"""
   TubeChar  R10, R11, "ADD R11, R12, #""0"""
   AND   R12, R10, #&F
   TubeChar  R10, R11, "ADD R11, R12, #""0"""
   Pull  R12
     ]

        STRB    R10, KARTTx             ; assume always able to transmit?
        CMP     R10, #ACK+&F
        MOVNE   R11, #InitKbdWs
        STRNEB  R11, [R11]            ; clear "one byte of 2 byte seq had" flag

        Pull    "r0-r2, R10-R12, lr"
        SUBS    PC, R14, #4

 DCD 0 ; temp fudge

 [ Keyboard_Type = "A1A500"
  [ . :AND: 255 = 0
 DCB "S" ; Odd length, should throw us
  ]
DataA1Kbd
    =   A1CTRLLRow,  A1CTRLLCol,  CTRL_Down_Flag
    =   A1CTRLRRow,  A1CTRLRCol,  CTRL_Down_Flag
    =   A1SHIFTRRow, A1SHIFTRCol, SHIFT_Down_Flag
    =   A1SHIFTLRow, A1SHIFTLCol, SHIFT_Down_Flag
    =   A1R_Row,     A1R_Col,     R_Down_Flag
    =   A1T_Row,     A1T_Col,     T_Down_Flag
    =   A1Del_Row,   A1Del_Col,   Del_Down_Flag
    =   A1Copy_Row,  A1Copy_Col,  Copy_Down_Flag
    =   0
 ]

 [ Keyboard_Type = "A1A500"
  [ . :AND: 255 = 0
 DCB "K"
  ]
DataA500Kbd
    =   A500CTRLRow,  A500CTRLCol,  CTRL_Down_Flag
    =   A500SHIFTRow, A500SHIFTCol, SHIFT_Down_Flag
    =   A500R_Row,    A500R_Col,    R_Down_Flag
    =   A500T_Row,    A500T_Col,    T_Down_Flag
    =   A500Del_Row,  A500Del_Col,  Del_Down_Flag
    =   A500Copy_Row, A500Copy_Col, Copy_Down_Flag
    =   0
 ]

    ALIGN

        LTORG

PollTxBit ROUT

01      LDRB    R10, [R12, #IOCIRQSTAB]
        TST     R10, #KARTTxBit
        BEQ     %BT01
        MOV     pc, lr


SendAndPollRxBit ROUT

        Push    lr

     [ KeyboardDebungling
   Push  R12
   MOV   R12, R11, LSR #4
   TubeChar  R10, R11, "MOV R11, #""t"""
   TubeChar  R10, R11, "ADD R11, R12, #""0"""
   AND   R12, R11, #&F
   TubeChar  R10, R11, "ADD R11, R12, #""0"""
   Pull  R12
     ]

        STRB    R11, KARTTx

01      LDRB    R10, [R12, #IOCIRQSTAB]
        TST     R10, #KARTRxBit
        BEQ     %BT01

        MOV    r2, #IOC
        MOV    r0, #32
        BL     DoMicroDelay
        LDRB   R11, KARTRx              ; purge KART, or get reply

     [ KeyboardDebungling
   Push  R12
   MOV   R12, R11, LSR #4
   TubeChar  R10, R11, "MOV R11, #""r"""
   TubeChar  R10, R11, "ADD R11, R12, #""0"""
   AND   R12, R11, #&F
   TubeChar  R10, R11, "ADD R11, R12, #""0"""
   Pull  R12
     ]

        Pull   pc

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

SetUpKbd
; set up keyboard: initialise baud rate, send dummy, read dummy
        MOV     R12, #IOC               ; code ripped off from pmf.Key
        MOV     R0, #1
        STRB    R0, Timer3Low
        MOV     R0, #0
        STRB    R0, Timer3High
        STRB    R0, Timer3Go            ; baud rate set and going

        STRB    R0, KARTTx              ; send dummy

        MOV     r1, r13
        MOV     r13, #&8000             ; need a quick stack - scratchspace
        Push    r1                      ; probably the best bet.

        MOV     r0, #&800*2             ; magic delay
        MOV     r2, #IOC
        BL      DoMicroDelay

        LDMFD   r13, {r13}              ; finished with stack

        LDRB    R0, KARTRx              ; ensure no wally byte in KARTRx

        BL      PollTxBit
        MOV     R0, #HRDRESET           ; start reset protocol
        STRB    R0, KARTTx

        B       SetUpKbdReturn

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

KeyboardDebungling SETL {FALSE}

        END