Distils public docs into reference/keyboard-mouse/PROTOCOL.md for the level-1 Keyboard (27) / Mouse (26) device tests: - keyboard: 4800 8N1 RS-423, self-test via FD -> 01 00 00 00 (errors 3D/3E) - mouse: 4800 8O1 RS-232, self-test via 'T' -> 4-byte report (errors 3D/3E, >=0x20 fatal) - separate ports: DUART2 A=keyboard, B=mouse (NOT daisy-chained) MAME already has an LK201 device (src/mame/dec/lk201.cpp/.h) but no DEC mouse.
4.7 KiB
LK201 / LK401 protocol
What the firmware relies on. Sources: the VCB02 technical manual (EK-104AA-TM-001, LK201
chapter) and Linux drivers/input/keyboard/lkkbd.c. Anything marked verify comes from
secondary sources or memory and must be confirmed on this keyboard in Phase 3.
Physical layer
-
Asynchronous serial, 4800 baud, 8 data bits, no parity, 1 stop bit, full duplex.
-
RS-423-style single-ended levels. The keyboard has only a +12 V supply, so its output cannot swing negative; the real levels are measured in Phase 1.
-
Polarity is RS-232 style: idle (mark) is the low voltage, which is the opposite of a microcontroller UART, so both directions go through an inverter.
-
Connector: 4P4C modular. Per
lkkbd.c, looking at the plug with the cable downwards and the latch away from you, pins 1–4 left to right:Pin Signal 1 Data to keyboard (host TX) 2 Ground 3 +12 V 4 Data from keyboard (host RX) Modular cables can be straight or reversed, so verify at the end of the cable we use.
Power-up
On power-up, or after the host sends FD (power-up reset), the keyboard runs its self-test,
flashes the LEDs, and sends four bytes:
| Byte | Meaning |
|---|---|
| 1 | Keyboard ID, firmware (01) |
| 2 | Keyboard ID, hardware (verify: 00) |
| 3 | Error: 00 none, 3D key down at power-up, 3E self-test failed |
| 4 | Keycode of the key held down, or 00 |
The host then asks for the ID (AB), which returns two bytes. lkkbd.c tells an LK201 (01)
from an LK401 (02) by the second of them (verify).
Because the converter and the keyboard power up together, the power-up bytes are usually sent
before anyone is listening. The console's reset command sends FD to repeat them.
Keycodes and special responses
Every key sends a single byte from 56 to FB. The bytes B3–BB are responses, not keys:
| Byte | Name | Meaning |
|---|---|---|
B3 |
ALL UPS | The last down/up key was released: every key is now up |
B4 |
METRONOME | Auto-repeat tick (not used: elkay turns auto-repeat off) |
B5 |
OUTPUT ERROR | Keyboard's transmit buffer overflowed |
B6 |
INPUT ERROR | Keyboard received a bad command |
B7 |
KBD LOCKED | Acknowledges "inhibit transmission" |
B8 |
TEST MODE ACK | Acknowledges test mode |
B9 |
PREFIX KEYS DOWN | Precedes a list of held keys after a mode change |
BA |
MODE CHANGE ACK | Acknowledges a mode-set command |
The full keycode table is in keymap.md.
Divisions and modes
Keys are grouped into 14 divisions, and each division is in one of three modes:
| Mode | Bits | Behaviour |
|---|---|---|
| Down only | 00 |
Keycode on press, nothing on release |
| Auto-repeat down | 01 |
Keycode on press, then B4 repeats while held |
| Down/up | 11 |
Keycode on press, and again on release |
USB HID needs releases, so elkay sets every division to down/up and lets the host do the auto-repeat.
A mode-set command is one byte: 1 DDDD MM 0 (division in bits 6–3, mode in bits 2–1), so
down/up for division d is 0x86 | d << 3.
Releases in down/up mode
A release is reported by sending the same keycode again, except when the released key was
the only down/up key still held: then the keyboard sends B3 (ALL UPS) instead. So the firmware
keeps a set of held keys, toggles a key's state each time its code arrives, and clears the whole
set on B3. This is also what lkkbd.c does.
Commands (host → keyboard)
Parameter bytes have bit 7 set; the last byte of every command has bit 7 set, which is how the keyboard knows the command is complete.
| Bytes | Command |
|---|---|
FD |
Power-up reset (self-test, then the four power-up bytes) |
AB |
Request keyboard ID (two bytes back) |
D3 |
Reinstate defaults |
E9 |
Enable LK401 mode: separate codes for the Alt Function keys, right Compose and right Shift |
0x86 | d<<3 |
Division d to down/up mode (d = 1–14) |
13 p |
LEDs on, p = 0x80 | mask |
11 p |
LEDs off, p = 0x80 | mask |
99 |
Disable keyclick |
1B v |
Enable keyclick, volume v = 0x80 | 0–7 (0 loudest) |
B9 / BB v |
Disable / enable Ctrl-key click |
A1 / 23 v |
Disable / enable bell, with volume |
A7 |
Sound the bell |
LED mask bits: 01 Wait, 02 Compose, 04 Lock, 08 Hold Screen.
Initialisation sequence used by elkay
Taken from lkkbd_reinit(), with keyclick off:
AB request ID
D3 defaults
E9 LK401 mode
8E 96 9E … F6 divisions 1–14 to down/up
99 B9 keyclick and Ctrl click off
11 8F all LEDs off
The console's init command sends exactly this.