Compare commits
4 Commits
master
...
fn-hooks-w
| Author | SHA1 | Date |
|---|---|---|
|
|
64a482984d | |
|
|
113b172e3d | |
|
|
52a92c70e5 | |
|
|
e73304f6f5 |
|
|
@ -28,13 +28,13 @@ build/main.o: build/section_data_patch.bin build/section_isr.bin
|
||||||
--change-section-address .vectors=0xffe0 \
|
--change-section-address .vectors=0xffe0 \
|
||||||
--set-start 0x8000 build/section_data_patch.bin $@
|
--set-start 0x8000 build/section_data_patch.bin $@
|
||||||
|
|
||||||
build/enter_bsl.o: shellcode/enter_bsl.c
|
build/fn_hooks.o: shellcode/fn_hooks.c
|
||||||
@echo "Compiling shellcode..."
|
@echo "Compiling shellcode..."
|
||||||
$(QUIET)msp430-gcc -Os -mmcu=msp430f5510 -c $< -o $@
|
$(QUIET)msp430-gcc -Os -mmcu=msp430f5510 -c $< -o $@
|
||||||
|
|
||||||
# The main.o is an relocatable elf which we convert to an actual elf
|
# The main.o is an relocatable elf which we convert to an actual elf
|
||||||
# for IDA to like it. Also link in our own objects
|
# for IDA to like it. Also link in our own objects
|
||||||
build/main.elf: build/main.o build/enter_bsl.o
|
build/main.elf: build/main.o build/fn_hooks.o
|
||||||
@echo "Create main.elf..."
|
@echo "Create main.elf..."
|
||||||
$(QUIET)msp430-gcc -O0 -mmcu=msp430f5510 \
|
$(QUIET)msp430-gcc -O0 -mmcu=msp430f5510 \
|
||||||
-Wl,--section-start=.text=0x8000 \
|
-Wl,--section-start=.text=0x8000 \
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,7 @@ lowest 3 bits of key id and the column is the 4 bits above that
|
||||||
from the table below and C is the 0 indexed column. For example ~tab =
|
from the table below and C is the 0 indexed column. For example ~tab =
|
||||||
5 + (2<<3) = 21~.
|
5 + (2<<3) = 21~.
|
||||||
|
|
||||||
First row contains row id:s and first column is column id:s, rest of
|
First column contains row id:s and first row is column id:s, rest of
|
||||||
the table is the keys..
|
the table is the keys..
|
||||||
|
|
||||||
#+ATTR_HTML: :border 2 :rules all :frame border
|
#+ATTR_HTML: :border 2 :rules all :frame border
|
||||||
|
|
|
||||||
34
patch.py
34
patch.py
|
|
@ -63,9 +63,10 @@ scancode_table2 = [0x00, 0x35, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23,
|
||||||
|
|
||||||
# See README for full id => key mapping
|
# See README for full id => key mapping
|
||||||
key_id_ctrl = 17
|
key_id_ctrl = 17
|
||||||
key_id_caps = 20
|
key_id_fn = 0
|
||||||
key_id_backspace = 112
|
# key_id_caps = 20
|
||||||
key_id_backslash = 117
|
# key_id_backspace = 112
|
||||||
|
# key_id_backslash = 117
|
||||||
|
|
||||||
# Hex offsets to scancode tables in the raw original fw. These tables
|
# Hex offsets to scancode tables in the raw original fw. These tables
|
||||||
# will be overwritten by our modified tables above
|
# will be overwritten by our modified tables above
|
||||||
|
|
@ -98,23 +99,26 @@ def original_fw_valid(path):
|
||||||
m.update(orig.read())
|
m.update(orig.read())
|
||||||
return m.hexdigest() == orig_fw_md5
|
return m.hexdigest() == orig_fw_md5
|
||||||
|
|
||||||
def write_jump_to_bsl():
|
def write_handle_fn_key_handler_hooks():
|
||||||
'''Make fn + F1 + F4 jump to BSL (firmware update mode)'''
|
'''Add C hooks for doing stuff when fn + key(s) is pressed'''
|
||||||
# Replace mov instruction with a call to our own code for checking
|
|
||||||
# which F keys are currently pressed. If fn + F1 + F4 is pressed
|
|
||||||
# jump to 0x1000 (BSL entry addr).
|
|
||||||
|
|
||||||
# bytecode for asm 'call 0xa780; nop'
|
# bytecode for asm 'calla 0xa780; nop' (on_fn_key_down)
|
||||||
dest.seek(0x83a)
|
dest.seek(0x83a)
|
||||||
dest.write('b01280a70343'.decode('hex'))
|
dest.write('b01380a70343'.decode('hex'))
|
||||||
|
|
||||||
|
# calla #0xa8f0 (on_fn_key_up, INCREDIHACK: offest depends on size
|
||||||
|
# of on_fn_key_down since this is linked after)
|
||||||
|
dest.seek(0xa98)
|
||||||
|
dest.write('b01302a8'.decode('hex'))
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
# Remap caps to ctrl
|
# Remap caps to fn
|
||||||
scancode_table1[key_id_caps] = scancode_table1[key_id_ctrl]
|
# scancode_table1[key_id_caps] = scancode_table1[key_id_ctrl]
|
||||||
|
scancode_table1[key_id_caps] = scancode_table1[key_id_fn]
|
||||||
|
|
||||||
# Switch down backspace to \ and \ to backspace
|
# Switch down backspace to \ and \ to backspace
|
||||||
scancode_table1[key_id_backspace], scancode_table1[key_id_backslash] = \
|
# scancode_table1[key_id_backspace], scancode_table1[key_id_backslash] = \
|
||||||
scancode_table1[key_id_backslash], scancode_table1[key_id_backspace]
|
# scancode_table1[key_id_backslash], scancode_table1[key_id_backspace]
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
description='Patch utility for Novatouch TKL firmware')
|
description='Patch utility for Novatouch TKL firmware')
|
||||||
|
|
@ -141,4 +145,4 @@ if __name__ == '__main__':
|
||||||
for text in usb_hid_strings:
|
for text in usb_hid_strings:
|
||||||
write_usb_string(dest, text)
|
write_usb_string(dest, text)
|
||||||
|
|
||||||
write_jump_to_bsl()
|
write_handle_fn_key_handler_hooks()
|
||||||
|
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
#include <intrinsics.h>
|
|
||||||
#include <msp430f5510.h>
|
|
||||||
|
|
||||||
// Declare pointers to variables we access in Novatouch fw
|
|
||||||
unsigned char* const repeat_flags = (unsigned char*)0x2404;
|
|
||||||
unsigned char* const repeat_rate = (unsigned char*)0x252f;
|
|
||||||
unsigned char* const num_for_7x_c1 = (unsigned char*)0x2530;
|
|
||||||
|
|
||||||
void check_bsl_enter() {
|
|
||||||
// We just replaced this copy to get here, perform it here instead
|
|
||||||
// (although it seems to be redundant because it is never actually
|
|
||||||
// read)
|
|
||||||
*num_for_7x_c1 = *repeat_rate;
|
|
||||||
|
|
||||||
// Enter BSL if fn + f1 + f4 is pressed
|
|
||||||
if ((*repeat_flags & 0x9) == 0x09) {
|
|
||||||
__dint();
|
|
||||||
// Maybe need to slow down clock to 8 MHz also, not sure what
|
|
||||||
// is configured by Novatouch fw
|
|
||||||
USBKEYPID = 0x9628;
|
|
||||||
USBCNF &= ~PUR_EN;
|
|
||||||
USBPWRCTL &= ~VBOFFIE;
|
|
||||||
USBKEYPID = 0x9600;
|
|
||||||
((void (*)())0x1000)();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,142 @@
|
||||||
|
#include <msp430f5510.h>
|
||||||
|
|
||||||
|
// Declare pointers to variables we access in Novatouch fw
|
||||||
|
unsigned char* const repeat_flags = (unsigned char*)0x2404;
|
||||||
|
unsigned char* const repeat_rate = (unsigned char*)0x252f;
|
||||||
|
unsigned char* const num_for_7x_c1 = (unsigned char*)0x2530;
|
||||||
|
unsigned char* const current_keycode = (unsigned char*)0x2400;
|
||||||
|
|
||||||
|
// Defines for internal scancodes (corresponding to scancode_table_1). Find out
|
||||||
|
// missing ones by using table at bottom of README.org.
|
||||||
|
//#define KEY_H 0x24
|
||||||
|
//#define KEY_J 0x25
|
||||||
|
//#define KEY_K 0x26
|
||||||
|
//#define KEY_L 0x27
|
||||||
|
#define KEY_W 0x0
|
||||||
|
#define KEY_A 0x0
|
||||||
|
#define KEY_S 0x0
|
||||||
|
#define KEY_D 0x0
|
||||||
|
#define KEY_Z 0x0
|
||||||
|
#define KEY_C 0x0
|
||||||
|
#define KEY_R 0x0
|
||||||
|
#define KEY_F 0x0
|
||||||
|
#define KEY_UP 0x53
|
||||||
|
#define KEY_DOWN 0x54
|
||||||
|
#define KEY_LEFT 0x4f
|
||||||
|
#define KEY_RIGHT 0x59
|
||||||
|
#define KEY_SPACE 0x0
|
||||||
|
#define KEY_BACKSPACE 0x0
|
||||||
|
#define KEY_HOME 0x0
|
||||||
|
#define KEY_END 0x0
|
||||||
|
#define KEY_PAGEUP 0x0
|
||||||
|
#define KEY_PAGEDOWN 0x0
|
||||||
|
#define KEY_TAB 0x0
|
||||||
|
#define KEY_CAPSLOCK 0x0
|
||||||
|
|
||||||
|
// Seems like original FW is compiled with IAR compiler and has different
|
||||||
|
// calling convention than mspgcc. Use macro to call functions and get correct
|
||||||
|
// parameter passing.
|
||||||
|
#define QUEUE_KEY(code) asm("mov.b %0, r12\n" \
|
||||||
|
"calla #0x91a2" : : "i"(code))
|
||||||
|
|
||||||
|
#define UNQUEUE_KEY(code) asm("mov.b %0, r12\n" \
|
||||||
|
"calla #0x9086" : : "i"(code))
|
||||||
|
|
||||||
|
// To be called when key is pressed and fn is also pressed
|
||||||
|
void on_fn_key_down() {
|
||||||
|
// We just replaced this copy to get here, perform it here instead
|
||||||
|
// (although it seems to be redundant because it is never actually
|
||||||
|
// read)
|
||||||
|
*num_for_7x_c1 = *repeat_rate;
|
||||||
|
|
||||||
|
// Enter BSL if fn + f1 + f4 is pressed
|
||||||
|
if ((*repeat_flags & 0x9) == 0x09) {
|
||||||
|
__dint();
|
||||||
|
// Maybe need to slow down clock to 8 MHz also, not sure what
|
||||||
|
// is configured by Novatouch fw
|
||||||
|
USBKEYPID = 0x9628;
|
||||||
|
USBCNF &= ~PUR_EN;
|
||||||
|
USBPWRCTL &= ~VBOFFIE;
|
||||||
|
USBKEYPID = 0x9600;
|
||||||
|
((void (*)())0x1000)();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extra bindings for fn + key
|
||||||
|
switch (*current_keycode) {
|
||||||
|
case KEY_A:
|
||||||
|
QUEUE_KEY(KEY_LEFT);
|
||||||
|
break;
|
||||||
|
case KEY_S:
|
||||||
|
QUEUE_KEY(KEY_DOWN);
|
||||||
|
break;
|
||||||
|
case KEY_W:
|
||||||
|
QUEUE_KEY(KEY_UP);
|
||||||
|
break;
|
||||||
|
case KEY_D:
|
||||||
|
QUEUE_KEY(KEY_RIGHT);
|
||||||
|
break;
|
||||||
|
case KEY_SPACE:
|
||||||
|
QUEUE_KEY(KEY_BACKSPACE);
|
||||||
|
break;
|
||||||
|
case KEY_Z:
|
||||||
|
QUEUE_KEY(KEY_HOME);
|
||||||
|
break;
|
||||||
|
case KEY_C:
|
||||||
|
QUEUE_KEY(KEY_END);
|
||||||
|
break;
|
||||||
|
case KEY_R:
|
||||||
|
QUEUE_KEY(KEY_PAGEUP);
|
||||||
|
break;
|
||||||
|
case KEY_F:
|
||||||
|
QUEUE_KEY(KEY_PAGEDOWN);
|
||||||
|
break;
|
||||||
|
case KEY_TAB:
|
||||||
|
QUEUE_KEY(KEY_CAPSLOCK);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// To be called when key is released and fn is also down
|
||||||
|
void on_fn_key_up() {
|
||||||
|
|
||||||
|
// Extra bindings for fn + key
|
||||||
|
switch (*current_keycode) {
|
||||||
|
case KEY_A:
|
||||||
|
UNQUEUE_KEY(KEY_LEFT);
|
||||||
|
break;
|
||||||
|
case KEY_S:
|
||||||
|
UNQUEUE_KEY(KEY_DOWN);
|
||||||
|
break;
|
||||||
|
case KEY_W:
|
||||||
|
UNQUEUE_KEY(KEY_UP);
|
||||||
|
break;
|
||||||
|
case KEY_D:
|
||||||
|
UNQUEUE_KEY(KEY_RIGHT);
|
||||||
|
break;
|
||||||
|
case KEY_SPACE:
|
||||||
|
UNQUEUE_KEY(KEY_BACKSPACE);
|
||||||
|
break;
|
||||||
|
case KEY_Z:
|
||||||
|
UNQUEUE_KEY(KEY_HOME);
|
||||||
|
break;
|
||||||
|
case KEY_C:
|
||||||
|
UNQUEUE_KEY(KEY_END);
|
||||||
|
break;
|
||||||
|
case KEY_R:
|
||||||
|
UNQUEUE_KEY(KEY_PAGEUP);
|
||||||
|
break;
|
||||||
|
case KEY_F:
|
||||||
|
UNQUEUE_KEY(KEY_PAGEDOWN);
|
||||||
|
break;
|
||||||
|
case KEY_TAB:
|
||||||
|
UNQUEUE_KEY(KEY_CAPSLOCK);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Moar ugly hacks! To hook this function we replaced the
|
||||||
|
// original call to unqueue key, setup original argument and
|
||||||
|
// do the call.
|
||||||
|
asm("mov.b &0x2400, r12\n"
|
||||||
|
"calla #0x9086");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue