Eager to get the remaining scan codes for the keyboard, I started thinking about exploring the keyboard emulation aspect. The product apparently works in two modes: 'standalone', which is what I've considered so far, and 'keyboard emulation' which is when it is attached to a desktop machine. The keyboard emulation provides for file sending, which has been discussed a bit, but also as a general purpose keyboard. This means that the various non-printing keys (shift, ctrl, F-keys, etc) are sent to the desktop, so there must be native AlphaSmart Pro scan code to standard (PS/2, ADB) scan code conversion somewhere. And since PS/2 and ADB are documented, I should be able to correlate.
Knowing from prior experience with PS/2 that the first sequence when a PS/2 keyboard is attached is to receive a 'reset' command (0xff), and respond with an 'ack' (0xfa) and the 'passed self test' (0xaa), I did a textual search of #$AA in hopes of maybe finding such. There was one reference with that text.
Address Function Instruction ------- -------- ----------- XROM:E2B7 sub_E265 86 AA ldaa #$AA
to
E2B4 loc_E2B4:
E2B4 BD E2 BE jsr sub_E2BE
E2B7 86 AA ldaa #$AA
E2B9 BD F7 A0 jsr sub_F7A0
E2BC 39 rts
Maybe this could be PS/2 emulation related? I was in luck. The sub_E2BE prior to that seems to be loading 0xFA:
E2BE sub_E2BE:
E2BE 86 FA ldaa #$FA
E2C0 BD F7 A0 jsr sub_F7A0
E2C3 39 rts
and they both call sub_F7A0 after. So that's probably the 'send PS/2 byte' function. There's a bunch of I/O bit fiddling and delays based on 'send speed', so there will be a bit of work to do in there. This shouldn't be too bad since PS/2 is a documented protocol.
This led up to a chain that is clearly the PS/2 host command handler. Most of the stuff is ignored, but some critical things like 'reset' and 'echo' and 'identify' and 'get scan code set' are important.
E265 ps2HandleCommand_E265:
E265 BD E2 FE jsr ps2GetByte_E2FE ; XXX ps2 get byte
E268 29 49 bvs leave_E2B3
E26A 96 72 ldaa byte_72
E26C 81 FF cmpa #$FF ; 'reset and self-test'
E26E 27 44 beq ps2ResetResponse_E2B4
E270 81 FE cmpa #$FE ; 'resend last byte'
E272 27 49 beq locret_E2BD ; just ignore; no ACK needed
E274 81 FD cmpa #$FD ; 'set specific key to make only'
E276 27 60 beq ps2EatNack_E2D8 ; PS/2 eat-and-ack for ignored commands
E278 81 FC cmpa #$FC ; 'set specific key to make/release'
E27A 27 5C beq ps2EatNack_E2D8 ; PS/2 eat-and-ack for ignored commands
E27C 81 FB cmpa #$FB ; 'set specific key to typematic/autorepeat only'
E27E 27 58 beq ps2EatNack_E2D8 ; PS/2 eat-and-ack for ignored commands
E280 81 FA cmpa #$FA ; 'set all keys to typematic/autorepeat/make/release'
E282 27 2C beq ps2AckIgnore_E2B0 ; PS/2 just ack for ignored commands
E284 81 F9 cmpa #$F9 ; 'set all keys to make only'
E286 27 28 beq ps2AckIgnore_E2B0 ; PS/2 just ack for ignored commands
E288 81 F8 cmpa #$F8 ; 'set all keys to make/release'
E28A 27 24 beq ps2AckIgnore_E2B0 ; PS/2 just ack for ignored commands
E28C 81 F7 cmpa #$F7 ; 'set all keys to typematic/autorepeat only'
E28E 27 20 beq ps2AckIgnore_E2B0 ; PS/2 just ack for ignored commands
E290 81 F6 cmpa #$F6 ; 'set default parameters'
E292 27 1C beq ps2AckIgnore_E2B0 ; PS/2 just ack for ignored commands
E294 81 F5 cmpa #$F5 ; 'disable scanning'
E296 27 18 beq ps2AckIgnore_E2B0 ; PS/2 just ack for ignored commands
E298 81 F4 cmpa #$F4 ; 'enable scanning'
E29A 27 14 beq ps2AckIgnore_E2B0 ; PS/2 just ack for ignored commands
E29C 81 F3 cmpa #$F3 ; 'set typematic rate and delay'
E29E 27 38 beq ps2EatNack_E2D8 ; PS/2 eat-and-ack for ignored commands
E2A0 81 F2 cmpa #$F2 ; 'identify keyboard'
E2A2 27 26 beq ps2IdentifyKeyboard_E2CA
E2A4 81 F0 cmpa #$F0 ; 'get/set current scan code set'
E2A6 27 3A beq ps2scanCodeSet_E2E2
E2A8 81 EE cmpa #$EE ; 'echo'; used for liveness testing by controller
E2AA 27 18 beq ps2sendEcho_E2C4
E2AC 81 ED cmpa #$ED ; 'set LEDs'
E2AE 27 28 beq ps2EatNack_E2D8 ; PS/2 eat-and-ack for ignored commands
E2B0 ps2AckIgnore_E2B0:
E2B0 BD E2 BE jsr ps2SendAck_E2BE ; PS/2 just ack for ignored commands
E2B3 leave_E2B3:
E2B3 39 rts
From this, we can also confirm that this device is emulating 'scan code set 2'. No surprise, as this is the most common, and the only one guaranteed to be supported, but it's still good to confirm.
The way this scan code set works is that there is a 'make' code (when key down), and a 'break' code (when key up). The 'make' code is usually a single byte, and the 'break' code has a prefix of 0xF0 followed by that same byte. There are a few keys that involve two-byte make codes (prefixed with 0xe0) and have three-byte break codes (prefixed with 0xe0, 0xf0).
Looking back at the scan code mapped structures at F8C5, there are byte values at offset +0 and +1 that I hadn't figured out yet. Making a spot check of a few keys and correlating that to PS/2 documentation for 'scan code set 2', it is strongly suggestive that offset +1 is the 'base' PS/2 code (i.e., without the 0xf0 or 0xe0 prefix, which is probably programmatically supplied).
FA75 0E fcb $E ; scan code 6c - 'E'
FA76 24 fcb $24 ; <- PS/2 scan code for 'E'!!!
FA77 65 fcb 'e'
FA78 45 fcb 'E'
FA79 0D fcb $D ; scan code 6d - 'W'
FA7A 1D fcb $1D ; <- PS/2 scan code for 'W'
FA7B 77 fcb 'w'
FA7C 57 fcb 'W'
FA7D 0C fcb $C ; scan code 6e - 'Q'
FA7E 15 fcb $15 ; <- PS/2 scan code for 'Q'
FA7F 71 fcb 'q'
FA80 51 fcb 'Q'
So I think there's another mystery solved. That should put some light on all the references to the +1 offset, so I've got some commenting and labelling to do....
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.