TL;DR: I picked up an IBM Lighted Program Function Keyboard (LPFK), wired its 8-pin mini-DIN to a modern USB-to-RS-232 dongle, reverse-engineered the “reset + enable + LED bitmap” protocol, and wrote a tiny Node.js app that prints keycodes and lights any key. This post documents the whole journey so you can repeat it (or just enjoy the rabbit hole).
The IBM Lighted Program Function Keyboard (LPFK) is a 32-key auxiliary pad,
each key with an independent, host-controlled indicator LED.
LPFKs were intended for graphics/CAD/CAM workflows on IBM workstations and displays on 1980s:
the IBM 5080/5085 graphics family in the mid-1980s and later RS/6000 systems (AIX),
with options to attach to PS/2 serial ports.
The device let software expose context-sensitive functions by lighting only the keys valid in the current state—an early,
physical “context menu.” Wikipedia Ardent Tool of Capitalism
A particularly common desktop unit is the IBM 6094-020 LPFK: 32 lighted keys, external 5V power, and a serial/aux interface. IBM field docs and parts lists reference the LPFK and its serial/power cable assemblies and FRUs for RS/6000/Power Systems, e.g., 39F8226 (LPFK, model 20) and 39F8302 (serial/power cable). IBM Public Cloud
I was hunting for other IBM gear (3178 terminal, 5160 PC/XT) when this LPFK popped up. It looked too interesting to pass up; I negotiated a bundle and ended up with two units. The plan: bring one to life on a modern Mac and keep the other as a spare (or donor).
This is a 3D model of my LPFK keyboard.
mini-DIN(male connector face):
6 7 8
3 4 5
1 2
DB9(male connector face):
1 2 3 4 5
6 7 8 9
mini-DIN Pin | Description | DB9 Pin | Description |
---|---|---|---|
5 | TX from LPFK | 2 | PC RX |
6 | RX to LPFK | 3 | PC TX |
1/2 | GND | 5 | Signal GND |
3/8 | +5 V input | 8 | +5 V input |
4/7 | not connected | 7 | not connected |
(This aligns with widely-shared community pinouts for the 6094-020 serial variant. The protocol itself doesn’t use RTS/CTS/DSR/DTR—only TX/RX/GND (+5 V).) brutman.com
Pro tip: If you aren’t sure the physical layer is right, short your adapter’s DB9 2↔3 and confirm local echo in a terminal. Only then bring the LPFK into the loop.
The LPFK I used has a two-position slide switch:
For host control, set it to ⚡, then do the reset + enable sequence (below).
/dev/tty.usbserial-…
picocom
3.1+ works well:
picocom --send-cmd "cat" -b 9600 -d 8 -p o --raise-dtr --raise-rts /dev/tty.usbserial-XXXXXX
Once the wiring+serial were right, the remaining barrier was mode and command bytes. After many attempts, I finally got the protocol right. The LPFK uses a simple byte protocol (no SOH frames needed):
0x01
= Reset (leaves device disabled, LEDs off)0x06
= Read Configuration (LPFK replies 0x03
)0x08
= Enable (enter reporting/controllable mode)0x09
= Disable0x94 <b0> <b1> <b2> <b3>
= Set Indicators (LED bitmap)0x00..0x1F
= Key press (32 keys)0x80
= Retransmit (LED bitmap parse error)0x81
= OK (LED bitmap accepted)Ready-to-send test files (macOS):
# reset / enable / disable
printf '\x01' > ~/LPFK/reset.bin
printf '\x08' > ~/LPFK/enable.bin
printf '\x09' > ~/LPFK/disable.bin
# clear and all-on
printf '\x94\x00\x00\x00\x00' > ~/LPFK/all_off.bin
printf '\x94\xff\xff\xff\xff' > ~/LPFK/all_on.bin
# single-key examples (light only 0x0A and 0x1F)
printf '\x94\x00\x20\x00\x00' > ~/LPFK/only_0a.bin # 0x0A
printf '\x94\x00\x00\x00\x01' > ~/LPFK/only_1f.bin # 0x1F
Picocom usage:
Ctrl-A S ~/LPFK/reset.bin
Ctrl-A S ~/LPFK/enable.bin
Ctrl-A S ~/LPFK/only_0a.bin
Heads-up: The device typically sends
0x81
after a valid0x94
bitmap (ACK). If you see0x80
, retransmit the bitmap.
Necessary boot ritual: After opening the port in ⚡ mode, you must send Reset (
01
) then Enable (08
). Before0x08
you’ll only see the “flash once” ack behavior; after0x08
, keycodes start flowing.
--imap 8bithex,lfhex,crhex,tabhex,spchex
to picocom.0x00..0x1F
. These are ASCII control chars; a dumb terminal turns some into newlines. Render as hex to see them clearly.0x94 b0 b1 b2 b3
): The four data bytes are little-endian groups, each group controls 8 keys:
b0
→ keys 00..07
b1
→ keys 08..0F
b2
→ keys 10..17
b3
→ keys 18..1F
4 + 6 + 6 + 6 + 6 + 4
), but the scan is linear left→right by rows:
I wrote a basic Node.js driver for the LPFK.
gist.github.com/ecrecover/lpfk.js
This minimal script will:
And here's a demo: