From 55ea3785290f84d2efd718465b834497eb3c47d6 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 4 Mar 2026 15:26:37 -0700 Subject: [PATCH] Add thelio io case revision and normalize commands with System76 EC --- keyboards/system76/system76_ec.c | 43 ++++++++++++++++---- keyboards/system76/system76_ec.h | 4 +- keyboards/system76/thelio_io_2/config.h | 17 ++++++++ keyboards/system76/thelio_io_2/thelio_io_2.c | 33 ++++++++++++--- 4 files changed, 84 insertions(+), 13 deletions(-) diff --git a/keyboards/system76/system76_ec.c b/keyboards/system76/system76_ec.c index fa15a79db14f..d3dcc7f38adb 100644 --- a/keyboards/system76/system76_ec.c +++ b/keyboards/system76/system76_ec.c @@ -21,6 +21,7 @@ #include "eeprom.h" #include "quantum.h" #include "raw_hid.h" +#include "thelio_io_2/config.h" #include "version.h" #ifdef DYNAMIC_KEYMAP_ENABLE #include "dynamic_keymap.h" @@ -48,7 +49,11 @@ enum Command { CMD_SET_NO_INPUT = 19, // Enable/disable no input mode CMD_SECURITY_GET = 20, // Get security state CMD_SECURITY_SET = 21, // Set security state - CMD_FAN_TACH = 22, // Get fan tachometer + CMD_FAN_GET_RPM = 22, // Get fan rpm + CMD_FAN_GET_MODE = 23, // Get fan mode + CMD_FAN_SET_MODE = 24, // Set fan mode + CMD_CASE_REV_GET = 25, // Get case revision + CMD_CASE_REV_SET = 26, // Set case revision }; bool input_disabled = false; @@ -103,7 +108,7 @@ __attribute__((weak)) bool system76_ec_fan_set(uint8_t index, uint8_t duty) { return false; } -__attribute__((weak)) bool system76_ec_fan_tach(uint8_t index, uint16_t * tach) { +__attribute__((weak)) bool system76_ec_fan_get_rpm(uint8_t index, uint16_t * rpm) { return false; } @@ -259,6 +264,20 @@ void system76_ec_rgb_layer(layer_state_t layer_state) { } #endif // RGB_MATRIX_CUSTOM_KB +// Read or write EEPROM data with checks for being inside System76 EC region. +bool system76_ec_case_rev(uint8_t *buf, size_t size, bool write) { +#ifdef SYSTEM76_EC_EEPROM_CASE_REV_ADDR + if (write) { + eeprom_update_block((const void *)buf, (void *)SYSTEM76_EC_EEPROM_CASE_REV_ADDR, size); + } else { + eeprom_read_block((void *)buf, (const void *)SYSTEM76_EC_EEPROM_CASE_REV_ADDR, size); + } + return true; +#endif + + return false; +} + void raw_hid_receive(uint8_t *data, uint8_t length) { // Error response by default, set to success by commands data[1] = 1; @@ -468,11 +487,11 @@ void raw_hid_receive(uint8_t *data, uint8_t length) { input_disabled = data[2] != 0; data[1] = 0; } break; - case CMD_FAN_TACH: { - uint16_t tach = 0; - if (system76_ec_fan_tach(data[2], &tach)) { - data[3] = (uint8_t)tach; - data[4] = (uint8_t)(tach >> 8); + case CMD_FAN_GET_RPM: { + uint16_t rpm = 0; + if (system76_ec_fan_get_rpm(data[2], &rpm)) { + data[3] = (uint8_t)rpm; + data[4] = (uint8_t)(rpm >> 8); data[1] = 0; } } break; @@ -486,6 +505,16 @@ void raw_hid_receive(uint8_t *data, uint8_t length) { data[1] = 0; } break; + case CMD_CASE_REV_GET: + if (system76_ec_case_rev(&data[2], SYSTEM76_EC_EEPROM_CASE_REV_SIZE, false)) { + data[1] = 0; + } + break; + case CMD_CASE_REV_SET: + if (system76_ec_case_rev(&data[2], SYSTEM76_EC_EEPROM_CASE_REV_SIZE, true)) { + data[1] = 0; + } + break; } raw_hid_send(data, length); diff --git a/keyboards/system76/system76_ec.h b/keyboards/system76/system76_ec.h index f20763fac49d..cf133c9edf73 100644 --- a/keyboards/system76/system76_ec.h +++ b/keyboards/system76/system76_ec.h @@ -35,10 +35,12 @@ bool system76_ec_is_unlocked(void); bool system76_ec_fan_get(uint8_t index, uint8_t * duty); bool system76_ec_fan_set(uint8_t index, uint8_t duty); -bool system76_ec_fan_tach(uint8_t index, uint16_t * tach); +bool system76_ec_fan_get_rpm(uint8_t index, uint16_t * tach); bool system76_ec_led_get_mode(uint8_t layer, uint8_t * mode, uint8_t * speed); bool system76_ec_led_set_mode(uint8_t layer, uint8_t mode, uint8_t speed); bool system76_ec_security_get(enum SecurityState * state); bool system76_ec_security_set(enum SecurityState state); + +bool system76_ec_case_rev(uint8_t *buf, size_t size, bool write); diff --git a/keyboards/system76/thelio_io_2/config.h b/keyboards/system76/thelio_io_2/config.h index 58e255b2a780..8a5338afd876 100644 --- a/keyboards/system76/thelio_io_2/config.h +++ b/keyboards/system76/thelio_io_2/config.h @@ -43,3 +43,20 @@ #define BACKLIGHT_BREATHING #define BACKLIGHT_LEVELS 31 #define BACKLIGHT_PERIOD 1 + +// EEPROM { +#define EEPROM_SIZE 1024 +// TODO: Refactor with new user EEPROM code (coming soon) +#define EEPROM_MAGIC 0x76EC +#define EEPROM_MAGIC_ADDR 64 +// Bump this every time we change what we store +// This will automatically reset the EEPROM with defaults +// and avoid loading invalid data from the EEPROM +#define EEPROM_VERSION 0x01 +#define EEPROM_VERSION_ADDR (EEPROM_MAGIC_ADDR + 2) +// } EEPROM + +// System76 EC { +#define SYSTEM76_EC_EEPROM_CASE_REV_ADDR (EEPROM_VERSION_ADDR + 1) +#define SYSTEM76_EC_EEPROM_CASE_REV_SIZE 4 +// } System76 EC diff --git a/keyboards/system76/thelio_io_2/thelio_io_2.c b/keyboards/system76/thelio_io_2/thelio_io_2.c index 1668114a78fb..504b57ce583b 100644 --- a/keyboards/system76/thelio_io_2/thelio_io_2.c +++ b/keyboards/system76/thelio_io_2/thelio_io_2.c @@ -16,6 +16,8 @@ */ #include "analog.h" +#include "config.h" +#include "eeprom.h" #include "../system76_ec.h" #include "thelio_io_2.h" @@ -186,6 +188,27 @@ void keyboard_pre_init_kb(void) { keyboard_pre_init_user(); } +bool eeprom_is_valid(void) { + return ( + eeprom_read_word(((void *)EEPROM_MAGIC_ADDR)) == EEPROM_MAGIC && + eeprom_read_byte(((void *)EEPROM_VERSION_ADDR)) == EEPROM_VERSION + ); +} +// clang-format on + +void eeprom_set_valid(bool valid) { + eeprom_update_word(((void *)EEPROM_MAGIC_ADDR), valid ? EEPROM_MAGIC : 0xFFFF); + eeprom_update_byte(((void *)EEPROM_VERSION_ADDR), valid ? EEPROM_VERSION : 0xFF); +} + +void matrix_init_kb(void) { + if (!eeprom_is_valid()) { + uint8_t rev[SYSTEM76_EC_EEPROM_CASE_REV_SIZE] = { 0 }; + system76_ec_case_rev(rev, SYSTEM76_EC_EEPROM_CASE_REV_SIZE, true); + eeprom_set_valid(true); + } +} + void keyboard_post_init_kb(void) { #ifdef CONSOLE_ENABLE // Set console verbosity @@ -416,19 +439,19 @@ bool system76_ec_fan_set(uint8_t index, uint8_t duty) { return true; } -bool system76_ec_fan_tach(uint8_t index, uint16_t * tach) { +bool system76_ec_fan_get_rpm(uint8_t index, uint16_t * rpm) { switch (index) { case 0: - *tach = FANOUT1.tach; + *rpm = FANOUT1.tach; return true; case 1: - *tach = FANOUT2.tach; + *rpm = FANOUT2.tach; return true; case 2: - *tach = FANOUT3.tach; + *rpm = FANOUT3.tach; return true; case 3: - *tach = FANOUT4.tach; + *rpm = FANOUT4.tach; return true; default: return false;