; Copyright 1999 Pace Micro Technology plc
;
; 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.
;
; > KbdResRCMM

; This file contains the minimal RCMM 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.

; These asserts are to do with the need to pull forward the combo chip configuration.
; As the code presently stands, ConfigureCombo will only work without calling
; ReadMachineType and PowerHardware in these conditions.
;
; The reason for not calling them is that they mess with variables and VIDC things
; that aren't ready yet.
;
; ConfigureCombo etc only write to IOSystemType, which has now been moved to SkippedTables
; so it doesn't get wiped by ClearPhysRam.

        ASSERT  :LNOT: BatManSupport

UART2                   * ComboBase + &2F8*4 ; -> base of UART 2

                        ^ 0, R2
UART_RBR                # 0     ; 0 Receive buffer register (read only)    { DLAB=0 }
UART_THR                # 4     ; 0 Transmit holding register (write only) { DLAB=0 }
UART_IER                # 4     ; 1 Interrupt enable register (RW)         { DLAB=0 }
UART_FCR                # 0     ; 2 FIFO control register (write only)
UART_IIR                # 4     ; 2 Interrupt identification register (read only)
UART_LCR                # 4     ; 3 Line control register
UART_MCR                # 4     ; 4 Modem control register
UART_LSR                # 4     ; 5 Line status register
UART_MSR                # 4     ; 6 Modem status register
UART_SCR                # 4     ; 7 Scratchpad register

                        ^ 0, R2
UART_DLL                # 4     ; 0 Divisor latch (LS)                     { DLAB=1 }
UART_DLH                # 4     ; 1 Divisor latch (MS)                     { DLAB=1 }


; States
                        ^ 0
RCMM_HaveNowt           # 1
RCMM_HaveBasic          # 1
RCMM_HaveOEM            # 1
RCMM_HaveOEM_Key        # 1
RCMM_HaveOEM_Remote     # 1
RCMM_HaveOEM_Remote_2   # 1

; RCMM keyboard codes we are interested in.
RCMMCtrlL       *       74
RCMMCtrlR       *       81
RCMMShiftL      *       61
RCMMShiftR      *       72
RCMMR           *       38
RCMMT           *       39
RCMMDelete      *       88
RCMMBSpace      *       33
RCMMEnd         *       89

; RCMM remote control codes we are interested in.

RCMMRemRight    *       91+128

KeyData
        DCB     RCMMCtrlL,    CTRL_Down_Flag
        DCB     RCMMCtrlR,    CTRL_Down_Flag
        DCB     RCMMShiftL,   SHIFT_Down_Flag
        DCB     RCMMShiftR,   SHIFT_Down_Flag
        DCB     RCMMR,        R_Down_Flag
        DCB     RCMMT,        T_Down_Flag
        DCB     RCMMDelete,   Del_Down_Flag
        DCB     RCMMBSpace,   Del_Down_Flag
        DCB     RCMMEnd,      Copy_Down_Flag
        DCB     RCMMRemRight, Del_Down_Flag
        DCB     0
        ALIGN

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

SetUpKbd
; Tricky - we don't have R13_svc set up yet - indeed it contains the RAM size
; and musn't be corrupted. These calls will need it though. The SVC stack does
; exist, so we can use it temporarily.
        MOV     R3, R13
        LDR     R13, =SVCSTK

; We're going to be using the serial port on the combo chip, so we need to
; pull forward the combo chip initialisation from PMF.osinit.
        [ STB
        BL      ConfigureCombo
        |
        BL      Configure37C665         ;RiscPC, Kryten and Stork use only SMC 37C665
        ]

; Set up the serial port

        LDR     R2, =UART2              ; R2 -> UART

        LDRB    R0, UART_LCR
        ORR     R1, R0, #2_10000000     ; set DLAB (enable Divisor Latch Access)
        STRB    R1, UART_LCR

        MOV     R1, #12                 ; divisor latch := 12 (9600 baud)
        STRB    R1, UART_DLL
        MOV     R1, #0
        STRB    R1, UART_DLH

        MOV     R0, #2_00000011         ; 8N1, DLAB off
        STRB    R0, UART_LCR

        STRB    R1, UART_FCR            ; FIFOs off

        LDRB    R0, UART_RBR            ; clear the receive buffer
        LDRB    R0, UART_RBR
        LDRB    R0, UART_LSR            ; clear any error condition

        MOV     R0, #2_00000101         ; received data and line status interrupts only
        STRB    R0, UART_IER

        MOV     R0, #2_00001011         ; enable IRQ; RTS and DTR on
        STRB    R0, UART_MCR

        MOV     R0, #IOMD_Base
 [ ReassignedIOMDInterrupts
        MOV     R1, #IOMDr_serial_IRQ_bit
 |
        MOV     R1, #IOMD_serial_IRQ_bit
 ]
        STRB    R1, [R0, #IOCIRQMSKB]

        MOV     R0, #InitKbdWs
        STRB    R1, [R0, #KB_There_Flag] ; keyboard is always there (it's infra-red...)

        MOV     R13, R3                 ; restore R13

        B       SetUpKbdReturn

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

; On ARM600, this routine must work in IRQ32 mode

; This is called on receipt of a serial interrupt.

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

        LDR     R2, =UART2
        LDRB    R0, UART_IIR
        AND     R1, R0, #2_00000111     ; check the interrupt source
        TEQ     R1, #2_100
        BEQ     IRQ_RCMM_Receive
        TEQ     R1, #2_110
        BEQ     IRQ_RCMM_LineStatus
        Pull    "R0-R2,PC",,^           ; shouldn't happen. Hope it goes away :)

IRQ_RCMM_LineStatus
        LDRB    R0, UART_LSR            ; this clears the interrupt
        TST     R0, #2_00011110         ; overrun, parity, framing or break error?
        Pull    "R0-R2,PC",EQ,^         ; no? then why did you call us?

        TST     R0, #2_00000001         ; data ready?
        LDRNEB  R0, UART_RBR            ; junk it then.

        MOV     R0, #RCMM_HaveNowt
        MOV     LR, #InitKbdWs
        STRB    R0, [LR, #KeyState]
        Pull    "R0-R2,PC",,^


; Problem we have is no flow control; we could be looking at any
; part of a message. Deal with this by resynchronising every time
; we get something we don't expect.

; Basic mode keypress is binary  10xx0kkk kkkk0000
; OEM mode keypress is binary    000011xx xxxx10xx 0kkkkkkk
;                             or 001xxxxx xxxx10xx 0kkkkkkk
; Remote control press is binary 000011xx xxxx00xx xxxxxxxx 0rrrrrrr
;                             or 001xxxxx xxxx00xx xxxxxxxx 0rrrrrrr

IRQ_RCMM_Receive
        LDRB    R0, UART_RBR            ; received data in R0 (interrupt cleared)
        MOV     R2, #InitKbdWs
        LDRB    LR, [R2, #KeyState]
        ADD     PC, PC, LR, LSL #2
        NOP
        B       IRQ_RCMM_Nowt
        B       IRQ_RCMM_Basic
        B       IRQ_RCMM_OEM
        B       IRQ_RCMM_OEM_Key
        B       IRQ_RCMM_OEM_Remote
        B       IRQ_RCMM_OEM_Remote_2

IRQ_RCMM_Nowt
        AND     LR, R0, #2_11001000
        TEQ     LR, #2_10000000         ; is it a basic mode keypress?
        BNE     %FT10

        MOV     LR, #RCMM_HaveBasic
        STRB    LR, [R2, #KeyState]
        AND     LR, R0, #2_00000111
        STRB    LR, [R2, #KeyMSB]

10      AND     LR, R0, #2_11111100     ; is it a short ID OEM message?
        TEQ     LR, #2_00001100
        ANDNE   LR, R0, #2_11100000     ; or a long ID one?
        TEQNE   LR, #2_00100000
        MOVEQ   LR, #RCMM_HaveOEM
        STREQB  LR, [R2, #KeyState]
        Pull    "R0-R2,PC",,^

IRQ_RCMM_Basic
        TST     R0, #2_00001111
        BNE     ResyncRCMM
        LDRB    LR, [R2, #KeyMSB]
        MOV     R0, R0, LSR #4
        ORR     R0, R0, LR, LSL #4      ; R0 = key code
        B       GotRCMMKey

IRQ_RCMM_OEM
        AND     LR, R0, #2_00001100
        TEQ     LR, #2_00000000         ; Remote control?
        TEQNE   LR, #2_00001000         ; Keyboard?
        BNE     ResyncRCMM
        TEQ     LR, #2_00000000
        MOVEQ   LR, #RCMM_HaveOEM_Remote
        MOVNE   LR, #RCMM_HaveOEM_Key
        B       UpdateRCMMState

IRQ_RCMM_OEM_Key
        TST     R0, #2_10000000         ; Key up rather than down?
        BNE     ResyncRCMM
        B       GotRCMMKey

IRQ_RCMM_OEM_Remote
        MOV     LR, #RCMM_HaveOEM_Remote_2
        B       UpdateRCMMState         ; This byte can be anything :)

IRQ_RCMM_OEM_Remote_2
        TST     R0, #2_10000000         ; Key up rather than down?
        BNE     ResyncRCMM
        ADD     R0, R0, #128            ; Indicate a remote code
        B       GotRCMMKey

ResyncRCMM
        MOV     LR, #RCMM_HaveNowt
UpdateRCMMState
        STRB    LR, [R2, #KeyState]
        Pull    "R0-R2,PC",,^

; In: R0 = key code, R2 = InitKbdWs
GotRCMMKey

        ADR     R1, KeyData
10
        LDRB    LR, [R1], #2            ; Get key code from table.
        TEQ     LR, #0                  ; If at end of table then
        Pull    "R0-R2,PC",EQ,^         ;   ignore key.

        TEQ     LR, R0                  ; If not this key then
        BNE     %BT10                   ;   try the next.

        LDRB    LR, [R1, #-1]           ; Get flag.
        STRB    LR, [R2, LR]            ; Non-zero means pressed.

        B       ResyncRCMM

        END