I recently acquired a Kinesis Freestyle 2 for Mac and really enjoy how it feels, but the layout is not quite to my taste. Having found http://alvarop.com/2013/08/kinesis-freestyle-2-keyboard-mod-to-fix-media-keys and https://github.com/rbasoalto/kinesis-freestyle-fw-hack I decided to follow along and am documenting my effort for the world to see.

Theory of Operation

At its core, this keyboard is little more than an wrapper around the Alcor Semiconductor AU9410 chip, which is probably how these things should be. The reference manual for that chip is, unfortunately, about as clear as mud, but so it goes.

Being a USB keyboard, the chip leans heavily on the USB HID standard, which may be found at http://www.usb.org/developers/hidpage/Hut1_12v2.pdf . This page will make heavy reference to said document as well, naturally enough.

In any case, there’s an I2C EEPROM off the board that is all that we really care about. This appears to hold a bunch of scary USB descriptors for the host (confusingly, the manual talks about putting hub descriptors here), some configuration of the chip itself, and, most importantly, an array of 4-byte values that correspond to the 19x8 keyboard matrix, at 0x1A0 bytes into this memory. (Which makes sense, as it’s a 0x400 byte memory and our array requires 0x260 bytes and 0x1A0 + 0x260 = 0x400.)

The keyboard has essentially two mappings for its keys: those when the FN switch is active and those when it’s not. The Kinesis boards use the AU9410’s ability to have the FN button toggle the mode rather than requre the FN button be pressed down. Moreover, when FN is active, the chip pulls LED2 on. These behaviors are documented in the manual (sort of):

  • Bit 4 of byte 1 in the EEPROM is 1 for FN toggling and 0 otherwise.

  • Bit 5 of byte 1 is 1 for FN mode to sink LED2 and 0 otherwise.

As far as I have been able to divine, there are three fields: a flag and page byte, a “fn-active” value (two bytes, from the USB HID page chosen by the page byte), and a “fn-inactive” value (1 byte, always from the HID keyboard codepage?).

Note

Because Kinesis uses the FN-toggle functionality, almost all of the keyboard’s “normal” keys are redundantly programmed, in that they look like (LSB) 00 00 VV VV (MSB) so that they function identically in FN-active and FN-inactive modes.

Integrated USB Hub

There’s a USB hub in the right half unit, too, based on a 4-port chip with only three of them actually used. Surely we can have fun with that! Since I2C is multi-master, we could maybe even stick an I2C to USB interface in there and use it to emulate the onboard EEPROM and act as if we can reprogram the keyboard live!

Firmware Layout

Based on my “for Mac” edition. It may be helpful to have http://kinesis-ergo.com/wp-content/uploads/2013/06/freestyle2-mac-layout-800x307.jpg open while looking at this table.

8 (00)

7 (04)

6 (08)

5 (0C)

4 (10)

3 (14)

2 (18)

1 (1C)

19 (1A0)

null

null

null

null

null

null

null

null

18 (1C0)

null

null

null

null

?r alt?

?r alt?

null

null

17 (1E0)

?eject?

?r shift?

tab back

tab fwd

web back

web fwd

left alt

?5 %?

16 (200)

?F1?

?Y?

copy

sel all

undo

l shift

r shift

?4 $?

15 (220)

end

home

left arr

null

up arr

?HUT 58?

?HUT 67?

?HUT 57?

14 (240)

pg down

pg up

?HUT 56?

?HUT 55?

?HUT 63?

?HUT 5B?

?HUT 5E?

?HUT 61?

13 (260)

null

off/slp

rght arr

?HUT 54?

?HUT 62?

?HUT 5A?

?HUT 5D?

?r shift?

12 (280)

eject

delete

down arr

?HUT 53?

left spc

?HUT 59?

?HUT 5C?

?r ctrl?

11 (2A0)

F10

F9

F12

return

F11

\ |

backspace

?r alt?

10 (2C0)

null

?V?

rght gui

?G?

left gui

?r ctrl?

cut

6

9 (2E0)

0 )

- _

/ ?

?HUT 32?

‘ “

; :

[ {

P

8 (300)

9 (

F8

null

. >

null

L

null

O

7 (320)

8 *

?= +?

?HUT 87?

, <

null

K

] }

I

6 (340)

?7?

null

N

M

H

J

Y

U

5 (360)

4 $

5 %

B

V

G

F

T

R

4 (380)

3 #

F2

r space

C

F4

D

F3

E

3 (3A0)

2 @

F1

F7

X

?HUT 64?

S

caps lock

W

2 (3C0)

1 !

` ~

F6

Z

escape

A

tab

Q

1 (3E0)

F5

l ctrl

paste

r alt

null

?delete?

?6?

?6?

“null” in the above table means that the bytes are 00 00 00 00 in my firmware dump, suggesting that there is no key at that position in the matrix in any product variant.

Note that this table is full of insanity! There’s no clear “keyboard cut in half” feel to it, suggesting that the inter-half linking cable is carrying many, many more wires than it would have to. WTF.

Additionally crazy are that some keycodes are duplicated. They have been marked above as ?x?; it is unclear what these are doing in the design. Perhaps the Kinesis keymaps are based on other products or are interchangable among several? The use of “?HUT xx?” indicates a key that’s really unusual; xx are the hex value from HUT keyboard page (0x07). Note that HUT 53 – HUT 63 are keypad scancodes; the tight packing of these scancodes into the rectangle bounded by 230 – 29C suggests either a version with a keypad or that the same firmware is used in the Kinesis standalone keypad product.

Note that the mac version of this product lacks a “r ctrl” key; it seems plausible that 2D4 is used on the PC version even if it is not on the mac? The positions for HUT 32 and HUT 87 are likely used on the internationalized variant.

Programming Header

The connector on the keyboard internal board is layed out as follows, when viewed with the keyboard opened but the board still in place. The silk screen with pin numbers is on the other side of the board, annoyingly enough.

GROUND (5)

SDA (4)

SCL (3)

Protect (2)

KEY

3.3V (1)

Protect is active-high and pulled high by default. Pull low to enable writing to the chip.

Example Interaction with Bus Pirate

http://ww1.microchip.com/downloads/en/devicedoc/21081G.pdf documents the EEPROM’s I2C protocol pretty well.

Switching Left Control and Caps Lock

  • [0xA6 0xE4][0xA7 r:4] reveals that left control is 0x00 0x00 0xE0 0xE0.

  • [0xA6 0xB8][0xA7 r:4] reveals that capslock is 0x00 0x00 0x39 0x39.

  • [0xA6 0xB8 0x00 0x00 0xE0 0xE0] sets capslock to actually scan as left control.

  • [0xA6 0xE4 0x00 0x00 0xE0 0x39] sets left control to actually scan as capslock when Fn is pressed and as control otherwise, since I happen to not like caps lock all that much.

Swapping Delete and Backslash

Similar to the above: [0xA4 0xB4 0x00 0x00 0x2A 0x2A][0xA4 0xB8 0x00 0x00 0x31 0x31] I’ve gone back and forth on this and am currently not so swapping these keys. Given the shape of the keyboard and how I type, it’s easier for me to hit the bigger delete key.

Making F keys non-Fn

While here, I kicked the keyboard over to the UNIX special keys for some of them.

F1

[0xA6 0xA4 0x00 0x00 0x3A 0x69] (F1 / F14)

F2

[0xA6 0x84 0x00 0x00 0x3B 0x6A] (F2 / F15)

F3

[0xA6 0x98 0x00 0x00 0x3C 0x74] (F3 / UNIX “Execute”; was 00 01 52 3C)

F4

[0xA6 0x90 0x00 0x00 0x3D 0x75] (F4 / UNIX “Help”; was 00 00 45 3D)

F5

[0xA6 0xE0 0x00 0x00 0x3E 0x7E] (F5 / UNIX “Find”; was 03 B6 00 3E)

F6

[0xA6 0xC8 0x00 0x00 0x3F 0x79] (F6 / UNIX “Again”; was 03 CD 00 3F)

F7

[0xA6 0xA8 0x00 0x00 0x40 0x76] (F7 / UNIX “Menu”; was 03 B5 00 40)

F8

[0xA6 0x04 0x40 0x00 0x7F 0x41] (swapped and UNIX Mute’d; was 03 E2 00 41)

F9

[0xA4 0xA4 0x40 0x00 0x81 0x42] (swapped and UNIX Vol Down’d; was 03 EA 00 42)

F10

[0xA4 0xA0 0x40 0x00 0x80 0x43] (swapped and UNIX Vol Up’d; was 03 E9 00 43)

F11

[0xA4 0xB0 0x40 0x01 0x51 0x44] (swapped; was 00 01 51 44)

F12

[0xA4 0xA8 0x40 0x0C 0x07 0x45] (swapped; was 00 0C 07 45)

UNIX-like Left Special Keys

Undo

Undo (both fn) [0xA4 0x10 0x00 0x00 0x7A 0x7A]

Cut

Cut (both fn) [0xA4 0xD8 0x00 0x00 0x7B 0x7B]

Copy

Copy (both fn) [0xA4 0x08 0x00 0x00 0x7C 0x7C]

Paste

Paste (both fn) [0xA6 0xE8 0x00 0x00 0x7D 0x7D]

Select All

Select (both fn) [0xA4 0x0C 0x00 0x00 0x77 0x77]

Swapping Home/End/PageUp/PageDown

Pos

Original | Now

220

00 00 4D 4D (end) | 00 00 4E 4E (pgdn)

224

00 00 4A 4A (home) | 00 00 4B 4B (pgup)

240

00 00 4E 4E (pgdn) | 00 00 4D 4D (end)

244

00 00 4B 4B (pgup) | 00 00 4A 4A (home)

Other Remappings

Power

Pause / Print Screen (with fn) [0xA4 0x64 0x00 0x00 0x48 0x46]

Eject

Insert (both fn) [0xA4 0x80 0x00 0x00 0x49 0x49]

Web Next

Escape (both fn) [0xA2 0xF4 0x00 0x00 0x29 0x29]

Web Back

Alt+Leftarrow / Stop (with fn) [0xA2 0xF0 0x00 0x04 0x50 0x78]