; 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. ; ; > Sources.PMF.KbdDrA1 ; Archimedes keyboard driver. ; *********************************** ; *** C h a n g e L i s t *** ; *********************************** ; Date Who Description ; ---- --- ----------- ; 24-Feb-93 SMC Split from file "key". ; Use generic keyboard/mouse interfaces. [ PollMouse K1ack * K1sack | K1ack * K1smak ] MACRO $lab RXonTXoff $reg, $cond $lab LDR$cond.B $reg, IRQMaskB BIC$cond $reg, $reg, #KARTTxBit ORR$cond $reg, $reg, #KARTRxBit STR$cond.B $reg, IRQMaskB MEND MACRO $lab TXonRXoff $reg, $cond $lab LDR$cond.B $reg, IRQMaskB BIC$cond $reg, $reg, #KARTRxBit ORR$cond $reg, $reg, #KARTTxBit STR$cond.B $reg, IRQMaskB MEND MACRO $lab RXon $reg, $cond $lab LDR$cond.B $reg, IRQMaskB ORR$cond $reg, $reg, #KARTRxBit STR$cond.B $reg, IRQMaskB MEND MACRO $lab TXon $reg, $cond $lab LDR$cond.B $reg, IRQMaskB ORR$cond $reg, $reg, #KARTTxBit STR$cond.B $reg, IRQMaskB MEND MACRO $lab TXoff $reg, $cond $lab LDR$cond.B $reg, IRQMaskB BIC$cond $reg, $reg, #KARTTxBit STR$cond.B $reg, IRQMaskB MEND GBLS irqregs irqregs SETS """R4-R10, PC""" ; ***************************************************************************** ; ; Start of code ArthurKeyDriver ; ***************************************************************************** ; ; Initialise driver. ; A1KeyInit ; Initialise the baud rate generator MOV R12, #IOC MOV R0, #1 STRB R0, Timer3Low MOV R0, #0 STRB R0, Timer3High STRB R0, Timer3Go STRB R0, KARTTx ; Write dummy byte MOV R0, #&800 10 SUBS R0, R0, #1 ; copy Jon's loop BNE %BT10 LDRB R0, KARTRx ; Read dummy byte [ AssemblePointerV MOV r0, #PointerV ADR r1, A1Pointer Push lr SWI OS_Claim Pull lr ] [ AssembleKEYV MOV r0, #KEYV ADR r1, A1KeyVec MOV r2, r12 Push lr SWI OS_Claim Pull pc | MOV pc, lr ] ; ***************************************************************************** ; ; Reset keyboard hardware. ; A1Reset MOV R0, #HRDRESET STRB R0, ResetState ASSERT HRDRESET = &FF STRB R0, KeyRow ; no key being received STRB R0, Reply STRB R0, LastKbId STRB R0, KbIdHalf STRB R0, RequestLED MOV R0, #K1rqid STRB R0, RequestKbId MOV R0, #0 STRB R0, JustGotKbId STRB R0, MouseCount ; start with an X coordinate STRB R0, SPDRec STRB R0, RequestSPD STRB R0, RequestMouse [ AssemblePointerV STR r0, MouseXCount STR r0, MouseYCount ] TXonRXoff R0 ; enable Tx IRQ, disable Rx IRQ MOV pc, lr ; ***************************************************************************** ; ; Handle enable and update LEDs (r1=state (bit 2=scroll, 1=num, 0=ctrl)). ; ; In: r0 = reason code 3 or 4 ; r1 = state (bit 2=scroll lock, 1=num lock, 0=caps lock) if r0=3 ; r12 = IOC ; A1KeyVec TEQ r0, #3 ; if not set LED TEQNE r0, #4 ; and not enable then MOVNE pc, lr ; pass it on Push "r0,r1,r11,lr" MOV r11, #KeyWorkSpace TEQ r0, #4 ; if enable then MOVEQ r0, #0 STREQB r0, JustGotKbId ; clear flag RXon r0, EQ ; enable RX IRQs Pull "r0,r1,r11,pc",EQ ; and pass on call LDRB r0, KbId CMP r0, #1 ; if id >= 1 then new (C=1) BCS %FT10 TST r1, #1 MOVEQ r1, #LEDOFF MOVNE r1, #LEDON 10 STRB r1, RequestLED TXon r0 Pull "r0,r1,r11,pc" [ AssemblePointerV ; ***************************************************************************** ; ; A1Pointer - Return mouse movements on PointerV poll. ; ; In: r0 = reason code 0 ; r1 = pointer device type (must be 0 for us) ; Out: r2 = signed 32-bit X movement ; r3 = signed 32-bit Y movement ; A1Pointer TEQ r0, #0 ; If not poll TEQEQ r1, #0 ; or not type 0 then MOVNE pc, lr ; pass on call. LDR r2, MouseXCount STR r0, MouseXCount LDR r3, MouseYCount STR r0, MouseYCount Pull pc ; Claim call. ] ; ***************************************************************************** ; ; IRQ routine ; ; in: R2 = IOC request B flags ; R0-R3, R11, R12 already saved, R14 irrelevant [ AssemblingArthur IrqRx ROUT Push "R4-R10, R14" ; stack regs if new MOS IRQ vector | KeyIrq ROUT TST R2, #KARTTxBit ; transmit empty ? BNE IrqTx Push "R4-R10" MOV R12, #IOC ; already set up in new IRQ scheme ] MOV R11, #KeyWorkSpace ; Keyboard receive interrupt ; We now have to wait around for a period of 16 microseconds (or so they say) ; because of the hardware design. ; This is doubly annoying because I have no idea what speed this processor is ; going at, so I don't know how many S-cycles this is, and there aren't enough ; hardware timers around to waste one doing this thankless task. ; In addition, because I am on the IRQ vector, the other IRQ users have ; probably wasted at least 16 microseconds anyway - at least the code seems ; to work perfectly well without this delay loop. ; Nevertheless, until we can come up with a better solution, I shall do a ; delay of (about) 16*8 S-cycles. ; MOV R0, #16*8/5 ; delay for an unspecified period IrqRxDelayLoop SUBS R0, R0, #1 ; this breaks my heart, BNE IrqRxDelayLoop ; it really does ! LDRB R0, KARTRx ; get data byte LDRB R1, ResetState ; and what we sent last CMP R0, #K1rak2 ; is it a reset thingy ? BCS ProcessReset ; [yes, so check it] CMP R1, #K1rak2 ; are we resetting anyway ? BCS IrqBadRx ; if so then bad reset AND R2, R0, #&F0 ; get reason code LDRB R1, LastKbId ; get last keyboard ID TEQ R1, #&FF ; is it valid yet ? BNE ValidKbId ; [yes, so we know what to expect] TEQ R2, #IDTYPE ; is it old keyboard id BEQ IsOldKeyboard ; [is old keyboard] BIC R2, R2, #K1kbidmask ; check for new keyboard id TEQ R2, #K1kbid BNE IrqBadRx ; not a keyboard id, so reset AND R1, R0, #K1kbidmask ; get relevant bits [ AssembleA1KeyHandler ADRL R0, NewKeyStruct ] B AcknowledgeId IsOldKeyboard AND R0, R0, #&0F ; get ID part LDRB R1, KbIdHalf TST R1, #&80 STRNEB R0, KbIdHalf ; got half of keyboard id MOVNE R0, #K1nack BNE IrqRxAck ORR R1, R1, R0, LSL #4 ; get full keyboard id MOV R0, #&FF STRB R0, KbIdHalf [ AssembleA1KeyHandler ADRL R0, OldKeyStruct ] AcknowledgeId [ AssembleA1KeyHandler LDRB R8, LastKbId ; get last keyboard id TEQ R8, R1 ; is it same STRNE R0, KeyVec ; if different, set up our handler ] MOV R0, #&FF STRB R0, JustGotKbId ; tell TX handler to disable interrupts until KEYV enable call [ AssembleKEYV MOV r0, #0 MOV r10, #KEYV BL CallVector | BL GotKbId ] B IrqRxAckScan ; send ack ; R1 = keyboard ID - now dispatch code ValidKbId TEQ R1, #0 BNE NewKeyboardDispatch OldKeyboardDispatch TST R0, #MMOVED ; is it mouse data ? BNE ProcessOldMouseData TEQ R2, #KEYDOWN ; is it key down ? BEQ ProcessOldKeyDown TEQ R2, #KEYUP ; is it key up ? BEQ ProcessOldKeyUp TEQ R2, #SPDDONE ; is it SPD data ? BEQ ProcessOldSPDData B IrqBadRx ; spurious NewKeyboardDispatch TST R2, #K1notmousedata ; is it mouse data ? BEQ ProcessNewMouseData TEQ R2, #K1kdda ; is it key down ? BEQ ProcessNewKeyDown TEQ R2, #K1kuda ; is it key up ? BEQ ProcessNewKeyUp TEQ R2, #K1pdat ; is it SPD data ? BEQ ProcessNewSPDData B IrqBadRx ; spurious ; ***************************************************************************** ; ; ProcessReset - Process reset code from keyboard ; ; in: R0 = code from keyboard ; R1 = ResetState ProcessReset ROUT ; Check sequencing TEQ R1, R0 ; is reply what was expected BNE IrqBadRx ; no, so reset ; Now continue the sequence TEQ R1, #K1rak2 ; end of sequence ? MOVEQ R1, #K1nack ; then send a nack SUBNE R1, R1, #1 ; else next thing to go STRB R1, ResetState ; store back TXonRXoff R0 Pull $irqregs IrqBadRx ; Restart the reset sequence BL A1Reset Pull $irqregs ; ***************************************************************************** ProcessOldSPDData ProcessNewSPDData LDRB R1, SPDRec SUBS R1, R1, #1 STRCSB R1, SPDRec ; dec number to go (if not 0) LDRCS R1, SPDoutput MOVCS R1, R1, LSR #4 ORRCS R1, R1, R0, LSL #28 ; put in new data STRCS R1, SPDoutput B IrqRxAckScan ; ***************************************************************************** ProcessOldMouseData ; R0 = 01xx xxxx TST R0, #&20 ; get sign bit of data (bit 5) BICEQ R0, R0, #&40 ; move to bit 6 (where it is on new) ProcessNewMouseData LDRB R1, MouseCount ADR R2, MouseDelta STRB R0, [R2, R1] ; no need to clear top bit EORS R1, R1, #1 ; move to other coordinate STRB R1, MouseCount MOVNE R0, #K1back BNE IrqRxAck LDRB R3, [R2, #1] ; get delta Y MOV R3, R3, LSL #25 ; sign extend it MOV R3, R3, ASR #25 LDRB R2, [R2] ; get delta X MOV R2, R2, LSL #25 ; sign extend it MOV R2, R2, ASR #25 [ AssemblePointerV LDR r0, MouseXCount ADD r0, r0, r2 STR r0, MouseXCount LDR r0, MouseYCount ADD r0, r0, r3 STR r0, MouseYCount | BL ProcessMouseXY ] B IrqRxAckScan ; ***************************************************************************** ; in: R1 = keyboard id ProcessOldKeyDown ProcessNewKeyDown ROUT LDRB R2, KeyRow TEQ R2, #&FF ; have we had a row already ? STREQB R0, KeyRow ; no so store row MOVEQ R0, #K1back BEQ IrqRxAck ; and acknowledge Rx EOR R3, R0, R2 ; test if save movement type TST R3, #&F0 BNE IrqBadRx ; not same, so reset AND R0, R0, #&0F ; get new data AND R2, R2, #&0F ; and row data TEQ R1, #0 ORREQ R2, R2, R0, LSL #4 ; old keyboard number ORRNE R2, R0, R2, LSL #4 ; new key number MOV R0, #&FF STRB R0, KeyRow ; reset 'had row' flag MOV r0, #2 ; indicate key down MOV r1, r2 [ AssembleKEYV MOV r10, #KEYV BL CallVector MOV r12, #IOC | BL GotKey ] IrqRxAckScan ; Re-enable Tx interrupts and queue an acknowledge MOV R0, #K1ack ; either sack or smak as appropriate IrqRxAck STRB R0, Reply TXonRXoff R0 Pull $irqregs ; claimed irq, so grab link and PC ; ***************************************************************************** ; in: R1 = keyboard id ProcessOldKeyUp ProcessNewKeyUp ROUT LDRB R2, KeyRow TEQ R2, #&FF ; have we had a row already ? STREQB R0, KeyRow ; no so store row MOVEQ R0, #K1back BEQ IrqRxAck ; and acknowledge Rx EOR R3, R0, R2 ; test if save movement type TST R3, #&F0 BNE IrqBadRx ; not same, so reset AND R0, R0, #&0F ; get new data AND R2, R2, #&0F ; and row data TEQ R1, #0 ORREQ R2, R2, R0, LSL #4 ; old key number ORRNE R2, R0, R2, LSL #4 ; new key number MOV R0, #&FF STRB R0, KeyRow ; reset 'had row' flag MOV r0, #1 ; indicate key up MOV r1, r2 [ AssembleKEYV MOV r10, #KEYV BL CallVector MOV r12, #IOC | BL GotKey ] B IrqRxAckScan ; ***************************************************************************** IrqTx ROUT [ AssemblingArthur Push "R4-R10, R14" ; stack regs if new MOS IRQ vector | Push "R4-R10" MOV R12, #IOC ; already set up in new IRQ scheme ] MOV R11, #KeyWorkSpace ; First see if we're in a reset sequence LDRB R0, ResetState ; are we in a reset ? TEQ R0, #0 BEQ %FT05 ; not in a reset CMP R0, #K1rak2 ; are we sending the reset nack ? BCS %FT25 ; no, just send reset code MOV R1, #0 ; yes, zero the reset state STRB R1, ResetState STRB R0, KARTTx Pull $irqregs ; don't disable TX ; Now see if any outstanding requests 05 LDRB R0, RequestSPD ; is there an SPD request ? TEQ R0, #0 BEQ %FT10 ; [no SPD request] MOV R1, #K1prst ; code to send keyboard MOV R2, #0 ; no further SPD request STRB R2, RequestSPD MOV R2, #8 STRB R2, SPDRec ; nibbles still to be sent/received STRB R1, KARTTx ; send the byte Pull $irqregs ; exit without disabling Tx 10 LDRB R0, RequestKbId ; is there a pending keyboard request ? TEQ R0, #0 MOVNE R1, #0 STRNEB R1, RequestKbId ; no further request STRNEB R0, KARTTx ; send the byte Pull $irqregs, NE ; exit without disabling Tx LDRB R0, RequestMouse ; is there a pending mouse request ? TEQ R0, #0 MOVNE R1, #0 STRNEB R1, RequestMouse ; no further request STRNEB R0, KARTTx Pull $irqregs, NE ; exit without disabling Tx LDRB R0, RequestLED ; is there a pending LED request ? TEQ R0, #&FF MOVNE R1, #&FF STRNEB R1, RequestLED STRNEB R0, KARTTx Pull $irqregs, NE ; exit without disabling Tx LDRB R0, SPDRec ; are we converting some SPD data TEQ R0, #0 BEQ %FT20 ; branch if not LDR R1, SPDinput AND R2, R1, #&F ; get nybble to be sent ORR R2, R2, #K1rqpd MOV R1, R1, LSR #4 ; shift out the nybble sent STR R1, SPDinput STRB R2, KARTTx B %FT30 ; disable Tx, so we don't send another ; nibble before we get the conversion 20 LDRB R0, Reply TEQ R0, #&FF BEQ %FT30 ; no reply to send 25 STRB R0, KARTTx ; send the reply MOV R0, #&FF STRB R0, Reply ; nothing else to send LDRB R0, JustGotKbId TEQ R0, #0 ; if just got keyboard id then TXoff R0, NE ; disable all interrupts Pull $irqregs, NE ; and wait for KEYV enable call 30 RXonTXoff R0 Pull $irqregs END