From 8f3778df605a1b88bd6d309d925e7ddb9ba02b2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Go=C5=82a=C5=9B?= Date: Fri, 17 Jul 2026 13:07:03 +0200 Subject: [PATCH 1/4] src/common/rng.c: Add an RNG library MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Filip Gołaś --- src/common/common.mk | 1 + src/common/include/common/rng.h | 12 +++++++++++ src/common/rng.c | 36 +++++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+) create mode 100644 src/common/include/common/rng.h create mode 100644 src/common/rng.c diff --git a/src/common/common.mk b/src/common/common.mk index 1b8ee6382..09c02043b 100644 --- a/src/common/common.mk +++ b/src/common/common.mk @@ -3,3 +3,4 @@ common-y += i2c.c common-y += keymap.c common-y += version.c +common-y += rng.c diff --git a/src/common/include/common/rng.h b/src/common/include/common/rng.h new file mode 100644 index 000000000..a4fd6f1a1 --- /dev/null +++ b/src/common/include/common/rng.h @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-3.0-only + +#ifndef _COMMON_RNG_H +#define _COMMON_RNG_H + +#include + +void rng_seed(uint16_t seed); +uint16_t simple_rng(void); +uint16_t nondeterministic_rng(void); + +#endif diff --git a/src/common/rng.c b/src/common/rng.c new file mode 100644 index 000000000..3b1937824 --- /dev/null +++ b/src/common/rng.c @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-3.0-only +// +#include +#include + +#define LFSR_MASK 0xB400u + +static uint16_t simple_rng_reg = -1U; +static uint16_t nondeterministic_rng_reg = -1U; + +void rng_seed(uint16_t seed) { + // 0 is invalid state, the generator locks up on 0 + uint16_t s = seed ? seed : -1U; + simple_rng_reg = s; + nondeterministic_rng_reg = s; +} + +uint16_t _galois_fsr(uint16_t lfsr) { + uint16_t bit = lfsr & 1U; + lfsr >>= 1U; + if (bit) { + lfsr ^= LFSR_MASK; + } + return lfsr; +} + +uint16_t simple_rng(void) { + simple_rng_reg = _galois_fsr(simple_rng_reg); + return simple_rng_reg; +} + +uint16_t nondeterministic_rng(void) { + nondeterministic_rng_reg += (uint16_t)(time_get()); + nondeterministic_rng_reg = _galois_fsr(nondeterministic_rng_reg); + return nondeterministic_rng_reg; +} From a1000099f24647d440d57b035010999a0998c23d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Go=C5=82a=C5=9B?= Date: Fri, 17 Jul 2026 14:27:50 +0200 Subject: [PATCH 2/4] Add Keyboard privacy key combo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Filip Gołaś --- src/common/include/common/keymap.h | 1 + src/keyboard/system76/14in_83/keymap/combo_iso_ansi.c | 4 ++-- src/keyboard/system76/14in_83/keymap/combo_iso_ansi_micmute.c | 2 +- src/keyboard/system76/15in_102/keymap/default.c | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/common/include/common/keymap.h b/src/common/include/common/keymap.h index 10a1a5d07..05fb8aa67 100644 --- a/src/common/include/common/keymap.h +++ b/src/common/include/common/keymap.h @@ -284,5 +284,6 @@ uint16_t keymap_translate(uint16_t key); #define KF_CUSTOM (0x0200) #define K_FNLOCK (KF_CUSTOM | 0x01) +#define K_KB_PRIVACY (KF_CUSTOM | 0x02) #endif // _COMMON_KEYMAP_H diff --git a/src/keyboard/system76/14in_83/keymap/combo_iso_ansi.c b/src/keyboard/system76/14in_83/keymap/combo_iso_ansi.c index 293d1064e..6d46b1934 100644 --- a/src/keyboard/system76/14in_83/keymap/combo_iso_ansi.c +++ b/src/keyboard/system76/14in_83/keymap/combo_iso_ansi.c @@ -17,9 +17,9 @@ LAYOUT_ISO( ), LAYOUT_ISO( K_ESC, K_TOUCHPAD, K_DISPLAY_TOGGLE, K_MUTE, K_KBD_BKL, K_VOLUME_DOWN, K_VOLUME_UP, K_DISPLAY_MODE, K_BRIGHTNESS_DOWN, K_BRIGHTNESS_UP, K_CAMERA_TOGGLE, K_AIRPLANE_MODE, K_SUSPEND, K_PRINT_SCREEN, K_PAUSE, K_NUM_LOCK, K_SCROLL_LOCK, - K_PLAY_PAUSE, K_FAN_TOGGLE, K_2, K_3, K_4, K_5, K_6, K_NUM_7, K_NUM_8, K_NUM_9, K_NUM_ASTERISK, K_MINUS, K_EQUALS, K_BKSP, + K_PLAY_PAUSE, K_FAN_TOGGLE, K_2, K_3, K_MIC_MUTE, K_5, K_6, K_NUM_7, K_NUM_8, K_NUM_9, K_NUM_ASTERISK, K_MINUS, K_EQUALS, K_BKSP, K_TAB, K_Q, K_W, K_E, K_R, K_T, K_Y, K_NUM_4, K_NUM_5, K_NUM_6, K_NUM_SLASH, K_BRACE_OPEN, K_BRACE_CLOSE, K_ENTER, - K_FNLOCK, K_A, K_S, K_D, K_F, K_G, K_H, K_NUM_1, K_NUM_2, K_NUM_3, K_NUM_MINUS, K_QUOTE, K_BACKSLASH, + K_FNLOCK, K_A, K_KB_PRIVACY, K_D, K_F, K_G, K_H, K_NUM_1, K_NUM_2, K_NUM_3, K_NUM_MINUS, K_QUOTE, K_BACKSLASH, K_LEFT_SHIFT, K_INT_1, K_Z, K_X, K_C, K_V, K_B, K_N, K_NUM_0, K_COMMA, K_NUM_PERIOD, K_NUM_PLUS, K_RIGHT_SHIFT, K_LEFT_CTRL, KT_FN, K_LEFT_SUPER, K_LEFT_ALT, K_SPACE, K_RIGHT_ALT, K_APP, K_HOME, K_UP, K_END, K_LEFT, K_DOWN, K_RIGHT diff --git a/src/keyboard/system76/14in_83/keymap/combo_iso_ansi_micmute.c b/src/keyboard/system76/14in_83/keymap/combo_iso_ansi_micmute.c index ebd3ffaac..6d46b1934 100644 --- a/src/keyboard/system76/14in_83/keymap/combo_iso_ansi_micmute.c +++ b/src/keyboard/system76/14in_83/keymap/combo_iso_ansi_micmute.c @@ -19,7 +19,7 @@ LAYOUT_ISO( K_ESC, K_TOUCHPAD, K_DISPLAY_TOGGLE, K_MUTE, K_KBD_BKL, K_VOLUME_DOWN, K_VOLUME_UP, K_DISPLAY_MODE, K_BRIGHTNESS_DOWN, K_BRIGHTNESS_UP, K_CAMERA_TOGGLE, K_AIRPLANE_MODE, K_SUSPEND, K_PRINT_SCREEN, K_PAUSE, K_NUM_LOCK, K_SCROLL_LOCK, K_PLAY_PAUSE, K_FAN_TOGGLE, K_2, K_3, K_MIC_MUTE, K_5, K_6, K_NUM_7, K_NUM_8, K_NUM_9, K_NUM_ASTERISK, K_MINUS, K_EQUALS, K_BKSP, K_TAB, K_Q, K_W, K_E, K_R, K_T, K_Y, K_NUM_4, K_NUM_5, K_NUM_6, K_NUM_SLASH, K_BRACE_OPEN, K_BRACE_CLOSE, K_ENTER, - K_FNLOCK, K_A, K_S, K_D, K_F, K_G, K_H, K_NUM_1, K_NUM_2, K_NUM_3, K_NUM_MINUS, K_QUOTE, K_BACKSLASH, + K_FNLOCK, K_A, K_KB_PRIVACY, K_D, K_F, K_G, K_H, K_NUM_1, K_NUM_2, K_NUM_3, K_NUM_MINUS, K_QUOTE, K_BACKSLASH, K_LEFT_SHIFT, K_INT_1, K_Z, K_X, K_C, K_V, K_B, K_N, K_NUM_0, K_COMMA, K_NUM_PERIOD, K_NUM_PLUS, K_RIGHT_SHIFT, K_LEFT_CTRL, KT_FN, K_LEFT_SUPER, K_LEFT_ALT, K_SPACE, K_RIGHT_ALT, K_APP, K_HOME, K_UP, K_END, K_LEFT, K_DOWN, K_RIGHT diff --git a/src/keyboard/system76/15in_102/keymap/default.c b/src/keyboard/system76/15in_102/keymap/default.c index 10c72cf88..041317b2f 100644 --- a/src/keyboard/system76/15in_102/keymap/default.c +++ b/src/keyboard/system76/15in_102/keymap/default.c @@ -18,7 +18,7 @@ LAYOUT( K_ESC, K_TOUCHPAD, K_DISPLAY_TOGGLE, K_MUTE, K_F4, K_VOLUME_DOWN, K_VOLUME_UP, K_DISPLAY_MODE, K_BRIGHTNESS_DOWN, K_BRIGHTNESS_UP, K_CAMERA_TOGGLE, K_AIRPLANE_MODE, K_SUSPEND, K_PRINT_SCREEN, K_SCROLL_LOCK, K_DEL, K_HOME, K_END, K_PAUSE, K_PAUSE, K_PLAY_PAUSE, K_FAN_TOGGLE, K_2, K_3, K_4, K_5, K_6, K_7, K_8, K_9, K_0, K_MINUS, K_EQUALS, K_BKSP, K_NUM_LOCK, K_KBD_COLOR, K_KBD_TOGGLE, K_KBD_DOWN, K_TAB, K_Q, K_W, K_E, K_R, K_T, K_Y, K_U, K_I, K_O, K_P, K_BRACE_OPEN, K_BRACE_CLOSE, K_BACKSLASH, K_NUM_7, K_NUM_8, K_NUM_9, K_KBD_UP, - K_FNLOCK, K_A, K_S, K_D, K_F, K_G, K_H, K_J, K_K, K_L, K_SEMICOLON, K_QUOTE, K_ENTER, K_NUM_4, K_NUM_5, K_NUM_6, + K_FNLOCK, K_A, K_KB_PRIVACY, K_D, K_F, K_G, K_H, K_J, K_K, K_L, K_SEMICOLON, K_QUOTE, K_ENTER, K_NUM_4, K_NUM_5, K_NUM_6, K_LEFT_SHIFT, K_Z, K_X, K_C, K_V, K_B, K_N, K_M, K_COMMA, K_PERIOD, K_SLASH, K_RIGHT_SHIFT, K_UP, K_NUM_1, K_NUM_2, K_NUM_3, K_NUM_ENTER, K_LEFT_CTRL, KT_FN, K_LEFT_SUPER, K_LEFT_ALT, K_SPACE, K_RIGHT_ALT, K_APP, K_RIGHT_CTRL, K_LEFT, K_DOWN, K_RIGHT, K_NUM_0, K_NUM_PERIOD ) From 13b823ea5c8c13098c34c94dc7be22b269cddfcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Go=C5=82a=C5=9B?= Date: Fri, 17 Jul 2026 14:44:01 +0200 Subject: [PATCH 3/4] Add keyboard privacy feature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Filip Gołaś --- .../system76/common/include/board/options.h | 2 ++ src/board/system76/common/kbc.c | 31 +++++++++++++++++-- src/board/system76/common/kbscan.c | 9 ++++++ src/board/system76/common/options.c | 2 ++ src/ec/ite/include/ec/kbc.h | 2 +- 5 files changed, 42 insertions(+), 4 deletions(-) diff --git a/src/board/system76/common/include/board/options.h b/src/board/system76/common/include/board/options.h index bc136450a..018075610 100644 --- a/src/board/system76/common/include/board/options.h +++ b/src/board/system76/common/include/board/options.h @@ -24,6 +24,8 @@ enum { OPT_ALLOW_BAT_BOOST, OPT_ALWAYS_ON_USB, OPT_GPU_MUX_CTRL, + OPT_KB_PRIVACY, + OPT_KB_PRIVACY_MAX_DELAY_MS, NUM_OPTIONS }; diff --git a/src/board/system76/common/kbc.c b/src/board/system76/common/kbc.c index aa9942b60..72ad8d943 100644 --- a/src/board/system76/common/kbc.c +++ b/src/board/system76/common/kbc.c @@ -1,11 +1,14 @@ // SPDX-License-Identifier: GPL-3.0-only +#include "include/board/options.h" #include +#include #include #include #include #include #include +#include #include #include @@ -80,10 +83,13 @@ static const uint16_t kbc_typematic_period[32] = { }; // clang-format on -static uint8_t kbc_buffer[16] = { 0 }; +static uint8_t kbc_buffer[32] = { 0 }; static uint8_t kbc_buffer_head = 0; static uint8_t kbc_buffer_tail = 0; +static bool kbc_buffer_privacy = false; +static uint8_t kbc_buffer_privacy_next_time = 0; + static bool kbc_buffer_pop(uint8_t *scancode) { if (kbc_buffer_head == kbc_buffer_tail) { return false; @@ -459,8 +465,23 @@ void kbc_event(struct Kbc *kbc) { uint8_t sts; // Read from scancode buffer when possible - if (state == KBC_STATE_NORMAL && kbc_buffer_pop(&state_data)) { - state = KBC_STATE_KEYBOARD; + if (state == KBC_STATE_NORMAL) { + if (options_get(OPT_KB_PRIVACY)) { + uint8_t time = time_get(); + if (time >= kbc_buffer_privacy_next_time) { + TRACE("KB_Priv: dleay of %d passed\n", kbc_buffer_privacy_next_time); + if (kbc_buffer_pop(&state_data)) { + state = KBC_STATE_KEYBOARD; + kbc_buffer_privacy_next_time = time + + (uint16_t)(nondeterministic_rng() % + (uint16_t)options_get(OPT_KB_PRIVACY_MAX_DELAY_MS)); + } + } + } else { + if (kbc_buffer_pop(&state_data)) { + state = KBC_STATE_KEYBOARD; + } + } } // Read from touchpad when possible @@ -521,3 +542,7 @@ void kbc_event(struct Kbc *kbc) { kbc_on_output_empty(kbc); } } + +void kbc_toggle_delay_randomization() { + options_set(OPT_KB_PRIVACY, options_get(OPT_KB_PRIVACY) ^ 1); +} diff --git a/src/board/system76/common/kbscan.c b/src/board/system76/common/kbscan.c index b4bd4d379..e4871e657 100644 --- a/src/board/system76/common/kbscan.c +++ b/src/board/system76/common/kbscan.c @@ -14,6 +14,7 @@ #include #include #include +#include // Default to not n-key rollover #ifndef KM_NKEY @@ -202,6 +203,13 @@ bool kbscan_press(uint16_t key, bool pressed, uint8_t *layer) { pmc_swi(); } + if (key == K_KB_PRIVACY && pressed) { + DEBUG("Toggling keyboard privacy\n"); + rng_seed(time_get()); + kbc_toggle_delay_randomization(); + return true; + } + if (key == K_FNLOCK && pressed) { DEBUG("Toggling FnLock\n"); keymap_fnlock ^= 1; @@ -316,6 +324,7 @@ static inline bool key_should_repeat(uint16_t key) { case K_CAMERA_TOGGLE: case K_DISPLAY_TOGGLE: case K_FAN_TOGGLE: + case K_KB_PRIVACY: case K_KBD_BKL: case K_KBD_COLOR: case K_KBD_TOGGLE: diff --git a/src/board/system76/common/options.c b/src/board/system76/common/options.c index 5d7b3d842..fe3d0bd68 100644 --- a/src/board/system76/common/options.c +++ b/src/board/system76/common/options.c @@ -17,6 +17,8 @@ uint8_t DEFAULT_OPTIONS[NUM_OPTIONS] = { [OPT_ALLOW_BAT_BOOST] = 0, [OPT_ALWAYS_ON_USB] = 0, [OPT_GPU_MUX_CTRL] = 0, + [OPT_KB_PRIVACY] = 0, + [OPT_KB_PRIVACY_MAX_DELAY_MS] = 100, }; // clang-format on diff --git a/src/ec/ite/include/ec/kbc.h b/src/ec/ite/include/ec/kbc.h index 2fb2e4440..e379f4a1e 100644 --- a/src/ec/ite/include/ec/kbc.h +++ b/src/ec/ite/include/ec/kbc.h @@ -35,7 +35,7 @@ uint8_t kbc_status(struct Kbc *kbc); uint8_t kbc_read(struct Kbc *kbc); bool kbc_keyboard(struct Kbc *kbc, uint8_t data, uint16_t timeout); bool kbc_mouse(struct Kbc *kbc, uint8_t data, uint16_t timeout); - +void kbc_toggle_delay_randomization(); volatile uint8_t __xdata __at(0x1300) KBHICR; volatile uint8_t __xdata __at(0x1302) KBIRQR; volatile uint8_t __xdata __at(0x1304) KBHISR; From e1e2353788e8cec82b841a69ffb4bc35711eb7a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Go=C5=82a=C5=9B?= Date: Wed, 22 Jul 2026 10:51:17 +0200 Subject: [PATCH 4/4] kbc.c: Fix kb privacy delay sometimes 0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Filip Lewiński Signed-off-by: Filip Gołaś --- src/board/system76/common/kbc.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/board/system76/common/kbc.c b/src/board/system76/common/kbc.c index 72ad8d943..06a75964f 100644 --- a/src/board/system76/common/kbc.c +++ b/src/board/system76/common/kbc.c @@ -88,7 +88,8 @@ static uint8_t kbc_buffer_head = 0; static uint8_t kbc_buffer_tail = 0; static bool kbc_buffer_privacy = false; -static uint8_t kbc_buffer_privacy_next_time = 0; +static uint32_t kbc_buffer_privacy_last_time = 0; +static uint16_t kbc_buffer_privacy_delay = 0; static bool kbc_buffer_pop(uint8_t *scancode) { if (kbc_buffer_head == kbc_buffer_tail) { @@ -467,14 +468,14 @@ void kbc_event(struct Kbc *kbc) { // Read from scancode buffer when possible if (state == KBC_STATE_NORMAL) { if (options_get(OPT_KB_PRIVACY)) { - uint8_t time = time_get(); - if (time >= kbc_buffer_privacy_next_time) { - TRACE("KB_Priv: dleay of %d passed\n", kbc_buffer_privacy_next_time); + uint32_t time = time_get(); + if (time - kbc_buffer_privacy_last_time >= (uint32_t)kbc_buffer_privacy_delay) { + TRACE("KB_Priv: delay of %d passed\n", kbc_buffer_privacy_delay); if (kbc_buffer_pop(&state_data)) { state = KBC_STATE_KEYBOARD; - kbc_buffer_privacy_next_time = time + - (uint16_t)(nondeterministic_rng() % - (uint16_t)options_get(OPT_KB_PRIVACY_MAX_DELAY_MS)); + kbc_buffer_privacy_last_time = time; + kbc_buffer_privacy_delay = (uint16_t)(nondeterministic_rng() % + options_get(OPT_KB_PRIVACY_MAX_DELAY_MS)); } } } else {