summaryrefslogtreecommitdiffhomepage
path: root/src/blog/fw-ec
diff options
context:
space:
mode:
Diffstat (limited to 'src/blog/fw-ec')
-rw-r--r--src/blog/fw-ec/1172.pngbin0 -> 17531 bytes
-rw-r--r--src/blog/fw-ec/fn-lock-1.diff.gsp12
-rw-r--r--src/blog/fw-ec/fn-lock-2.diff.gsp36
-rw-r--r--src/blog/fw-ec/hybrid.diff.gsp88
-rw-r--r--src/blog/fw-ec/index.gsp229
-rw-r--r--src/blog/fw-ec/kbd-sc-cb.c.gsp6
-rw-r--r--src/blog/fw-ec/led.diff.gsp32
7 files changed, 403 insertions, 0 deletions
diff --git a/src/blog/fw-ec/1172.png b/src/blog/fw-ec/1172.png
new file mode 100644
index 0000000..14b3be1
--- /dev/null
+++ b/src/blog/fw-ec/1172.png
Binary files differ
diff --git a/src/blog/fw-ec/fn-lock-1.diff.gsp b/src/blog/fw-ec/fn-lock-1.diff.gsp
new file mode 100644
index 0000000..f847e41
--- /dev/null
+++ b/src/blog/fw-ec/fn-lock-1.diff.gsp
@@ -0,0 +1,12 @@
+@span .diff-meta {-diff --git a/board/hx20/board.h b/board/hx20/board.h}
+@span .diff-meta {-index 7b4ea288a..cfc6a61a2 100644}
+@span .diff-meta {---- a/board/hx20/board.h}
+@span .diff-meta {-+++ b/board/hx20/board.h}
+@span .diff-loc {-\@\@ -218,7 +218,6 \@\@}
+ #define CONFIG_CMD_LEDTEST
+ #define CONFIG_LED_PWM_COUNT 3
+ #define CONFIG_LED_PWM_TASK_DISABLED
+@span .diff-del {--#define CONFIG_CAPSLED_SUPPORT}
+
+ #ifdef CONFIG_ACCEL_KX022
+ #define CONFIG_LID_ANGLE
diff --git a/src/blog/fw-ec/fn-lock-2.diff.gsp b/src/blog/fw-ec/fn-lock-2.diff.gsp
new file mode 100644
index 0000000..7f9e702
--- /dev/null
+++ b/src/blog/fw-ec/fn-lock-2.diff.gsp
@@ -0,0 +1,36 @@
+@span .diff-meta {-diff --git a/board/hx20/keyboard_customization.c b/board/hx20/keyboard_customization.c}
+@span .diff-meta {-index 2b91f2e0c..9a5050a0f 100644}
+@span .diff-meta {---- a/board/hx20/keyboard_customization.c}
+@span .diff-meta {-+++ b/board/hx20/keyboard_customization.c}
+@span .diff-loc {-\@\@ -249,6 +249,23 \@\@ int fn_table_set(int8_t pressed, uint32_t fn_bit)}
+ return false;
+ \}
+
+@span .diff-ins {-+static void hx20_update_fnkey_led(void) {}
+@span .diff-ins {-+ /* Turn the capslock light into a fn-lock light */}
+@span .diff-ins {-+ gpio_set_level(GPIO_CAP_LED_L, (Fn_key & FN_LOCKED) ? 1 : 0);}
+@span .diff-ins {-+\}}
+@span .diff-ins {-+}
+@span .diff-ins {-+/* Set the fn-lock light to the correct setting when the system resumes */}
+@span .diff-ins {-+void hx20_fnkey_resume(void) {}
+@span .diff-ins {-+ hx20_update_fnkey_led();}
+@span .diff-ins {-+\}}
+@span .diff-ins {-+DECLARE_HOOK(HOOK_CHIPSET_RESUME, hx20_fnkey_resume, HOOK_PRIO_DEFAULT);}
+@span .diff-ins {-+}
+@span .diff-ins {-+/* Disable the fn-lock light on suspend */}
+@span .diff-ins {-+void hx20_fnkey_suspend(void) {}
+@span .diff-ins {-+ gpio_set_level(GPIO_CAP_LED_L, 0);}
+@span .diff-ins {-+\}}
+@span .diff-ins {-+DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, hx20_fnkey_suspend, HOOK_PRIO_DEFAULT);}
+@span .diff-ins {-+}
+ void fnkey_shutdown(void) {
+ uint8_t current_kb = 0;
+
+@span .diff-loc {-\@\@ -420,6 +437,7 \@\@ int functional_hotkey(uint16_t *key_code, int8_t pressed)}
+ Fn_key &= ~FN_LOCKED;
+ else
+ Fn_key |= FN_LOCKED;
+@span .diff-ins {-+ hx20_update_fnkey_led();}
+ \}
+ return EC_ERROR_UNIMPLEMENTED;
+ \}
diff --git a/src/blog/fw-ec/hybrid.diff.gsp b/src/blog/fw-ec/hybrid.diff.gsp
new file mode 100644
index 0000000..dfd4518
--- /dev/null
+++ b/src/blog/fw-ec/hybrid.diff.gsp
@@ -0,0 +1,88 @@
+@span .diff-meta {-diff --git a/board/hx20/keyboard_customization.c b/board/hx20/keyboard_customization.c}
+@span .diff-meta {-index 9a5050a0f..2756f17ce 100644}
+@span .diff-meta {---- a/board/hx20/keyboard_customization.c}
+@span .diff-meta {-+++ b/board/hx20/keyboard_customization.c}
+@span .diff-loc {-\@\@ -22,12 +22,15 \@\@}
+ #define CPRINTS(format, args...) cprints(CC_KEYBOARD, format, ## args)
+ #define CPRINTF(format, args...) cprintf(CC_KEYBOARD, format, ## args)
+
+@span .diff-ins {-+/* The scancode for the caps-lock key, which is now a hybrid key */}
+@span .diff-ins {-+#define SCANCODE_CTRL_ESC 0x0101}
+@span .diff-ins {-+}
+ uint16_t scancode_set2[KEYBOARD_COLS_MAX][KEYBOARD_ROWS] = {
+ {0x0021, 0x007B, 0x0079, 0x0072, 0x007A, 0x0071, 0x0069, 0xe04A\},
+ {0xe071, 0xe070, 0x007D, 0xe01f, 0x006c, 0xe06c, 0xe07d, 0x0077\},
+ {0x0015, 0x0070, 0x00ff, 0x000D, 0x000E, 0x0016, 0x0067, 0x001c\},
+ {0xe011, 0x0011, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000\},
+@span .diff-del {-- {0xe05a, 0x0029, 0x0024, 0x000c, 0x0058, 0x0026, 0x0004, 0xe07a\},}
+@span .diff-ins {-+ {0xe05a, 0x0029, 0x0024, 0x000c, 0x0101, 0x0026, 0x0004, 0xe07a\},}
+ {0x0022, 0x001a, 0x0006, 0x0005, 0x001b, 0x001e, 0x001d, 0x0076\},
+ {0x002A, 0x0032, 0x0034, 0x002c, 0x002e, 0x0025, 0x002d, 0x002b\},
+ {0x003a, 0x0031, 0x0033, 0x0035, 0x0036, 0x003d, 0x003c, 0x003b\},
+@span .diff-loc {-\@\@ -497,6 +500,55 \@\@ int functional_hotkey(uint16_t *key_code, int8_t pressed)}
+ return EC_SUCCESS;
+ \}
+
+@span .diff-ins {-+int try_ctrl_esc(uint16_t *key_code, int8_t pressed) {}
+@span .diff-ins {-+ static enum {}
+@span .diff-ins {-+ NONE,}
+@span .diff-ins {-+ HELD,}
+@span .diff-ins {-+ CTRL}
+@span .diff-ins {-+ \} ctrl_esc_state;}
+@span .diff-ins {-+}
+@span .diff-ins {-+ if (*key_code == SCANCODE_CTRL_ESC) {}
+@span .diff-ins {-+ /* If we pressed the caps key, enter the HELD state. Otherwise,}
+@span .diff-ins {-+ * we are either releasing from the HELD state or the CTRL}
+@span .diff-ins {-+ * state. In both cases we should reset the state to NONE, but}
+@span .diff-ins {-+ * when releasing from the HELD state we want to send an ESC and}
+@span .diff-ins {-+ * when releasing from the CTRL state we want to end the CTRL.}
+@span .diff-ins {-+ *}
+@span .diff-ins {-+ * Also important to note is that even before we know if we’re}
+@span .diff-ins {-+ * going to be acting as ESC or CTRL, we need to send a press-}
+@span .diff-ins {-+ * event of the CTRL key because you can chord CTRL with mouse-}
+@span .diff-ins {-+ * clicks too, not just other keys.}
+@span .diff-ins {-+ */}
+@span .diff-ins {-+ if (pressed) {}
+@span .diff-ins {-+ ctrl_esc_state = HELD;}
+@span .diff-ins {-+ simulate_keyboard(SCANCODE_LEFT_CTRL, 1);}
+@span .diff-ins {-+ \} else if (ctrl_esc_state == HELD) {}
+@span .diff-ins {-+ ctrl_esc_state = NONE;}
+@span .diff-ins {-+ simulate_keyboard(SCANCODE_LEFT_CTRL, 0);}
+@span .diff-ins {-+ simulate_keyboard(SCANCODE_ESC, 1);}
+@span .diff-ins {-+ simulate_keyboard(SCANCODE_ESC, 0);}
+@span .diff-ins {-+ \} else if (ctrl_esc_state == CTRL) {}
+@span .diff-ins {-+ ctrl_esc_state = NONE;}
+@span .diff-ins {-+ simulate_keyboard(SCANCODE_LEFT_CTRL, 0);}
+@span .diff-ins {-+ \}}
+@span .diff-ins {-+}
+@span .diff-ins {-+ return EC_ERROR_UNIMPLEMENTED;}
+@span .diff-ins {-+ \}}
+@span .diff-ins {-+}
+@span .diff-ins {-+ /* If we get here then we are dealing with a key that isn’t the caps}
+@span .diff-ins {-+ * key. In that case we need to handle all 3 states. If the state is}
+@span .diff-ins {-+ * NONE then we can just exit from this function. If it’s HELD and we}
+@span .diff-ins {-+ * are pressing a key, then that’s a key-chord and we need to start a}
+@span .diff-ins {-+ * CTRL. Finally, if we are in the CTRL state, there is nothing to do.}
+@span .diff-ins {-+ */}
+@span .diff-ins {-+ if (ctrl_esc_state == HELD && pressed) {}
+@span .diff-ins {-+ ctrl_esc_state = CTRL;}
+@span .diff-ins {-+ simulate_keyboard(SCANCODE_LEFT_CTRL, 1);}
+@span .diff-ins {-+ \}}
+@span .diff-ins {-+}
+@span .diff-ins {-+ return EC_SUCCESS;}
+@span .diff-ins {-+\}}
+@span .diff-ins {-+}
+ enum ec_error_list keyboard_scancode_callback(uint16_t *make_code,
+ int8_t pressed)
+ {
+@span .diff-loc {-\@\@ -521,6 +573,10 \@\@ enum ec_error_list keyboard_scancode_callback(uint16_t *make_code,}
+ if (!pos_get_state())
+ return EC_SUCCESS;
+
+@span .diff-ins {-+ r = try_ctrl_esc(make_code, pressed);}
+@span .diff-ins {-+ if (r != EC_SUCCESS)}
+@span .diff-ins {-+ return r;}
+@span .diff-ins {-+}
+ r = hotkey_F1_F12(make_code, Fn_key, pressed);
+ if (r != EC_SUCCESS)
+ return r;
diff --git a/src/blog/fw-ec/index.gsp b/src/blog/fw-ec/index.gsp
new file mode 100644
index 0000000..acd39b9
--- /dev/null
+++ b/src/blog/fw-ec/index.gsp
@@ -0,0 +1,229 @@
+html lang="en" {
+ head { m4_include(head.gsp) }
+ body {
+ header {
+ div {
+ h1 {-Framework is Awesome}
+ m4_include(nav.gsp)
+ }
+
+ figure .quote {
+ blockquote {
+ p {=
+ UNIX was not designed to stop its users from doing stupid things, as
+ that would also stop them from doing clever things.
+ }
+ }
+ figcaption {-Doug Gywn}
+ }
+ }
+
+ main {
+ h2 {-Table of Contents}
+
+ ul {
+ li {a href="#framework" {-Framework and the EC}}
+ li {a href="#led" {-LED Fun!}}
+ li {a href="#more" {-There’s More Than One LED‽}}
+ li {a href="#hybrid" {-The Hybrid Key}}
+ li {a href="#next" {-What’s Next?}}
+ }
+
+ h2 #framework {-Framework and the m4_abbr(EC)}
+ p {-
+ @a href="https://frame.work" target="_blank" {-Framework}
+ — for those unaware — is the coolest laptop manufacturer ever. Their
+ whole @em{-shtick} is producing laptops that give the user the ability
+ to easily and effortlessly disassemble, repair, and modify their
+ hardware. I highly suggest checking them out if you’re interested in
+ computer hardware at all. The laptops even have hotswappable I/O!
+ }
+
+ p {-
+ Anyways getting back on topic, Framework has also been giving power to
+ the user on the software-side of things too! A good while ago they
+ open-sourced the
+ @a
+ href="https://github.com/FrameworkComputer/EmbeddedController"
+ target="_blank"
+ {-code for the embedded controller}
+ of their laptops, which offers all sorts of possibilities for
+ customization of the keyboard, m4_abbr(LED) lights, and more.
+ }
+
+ h2 #led {-m4_abbr(LED) Fun!}
+ p {-
+ This is an area of the m4_abbr(EC) which I have not really looked at or
+ touched much. I do want to play around with this a lot more in the
+ coming future though! So far just for shits-and-giggles, I’ve patched
+ the m4_abbr(EC) to make the power-button m4_abbr(LED) green instead of
+ the normal boring white:
+ }
+
+ aside {
+ p {-
+ Just a tip: if you want to try any of these patches out,
+ simply copy the diffs and paste them
+ into @code {-git apply}.
+ }
+ }
+
+ figure {
+ figcaption {
+ code {-~/board/hx20/led.c}
+ }
+ pre {= m4_fmt_code(led.diff.gsp) }
+ }
+
+ p {-
+ As you can see, it’s all fairly simple. I just had to change our
+ @code{-EC_LED_COLOR_WHITE} for @code{-EC_LED_COLOR_GREEN}. The codebase
+ defines a few colors, but they’re defined as m4_abbr(RGB) tuples which
+ is awesome, because it opens the door to custom m4_abbr(RGB) effects in
+ the future!
+ }
+
+ h2 #more {-There’s More Than One m4_abbr(LED)‽}
+ p {-
+ That’s right! The Framework laptop I own (13″; the 16″ releases soon
+ though!) has 3 more m4_abbr(LED) lights. One on the left of the
+ chassis, one on right of the chassis, and one on the capslock key. The
+ capslock m4_abbr(LED) acts as an indicator of whether or not you’ve got
+ capslock enabled. This is useless to me though, because my custom
+ keyboard layout doesn’t even support capslock (see the next section) —
+ so I patched it to be a function-lock indicator instead!
+ }
+
+ p {-
+ Here’s the diff — but do take care if you want to apply similar patches
+ to your laptop! The files I’m editing are under @code{-board/hx20}
+ since I’m on an 11th Gen Intel m4_abbr(CPU). If you have a different
+ m4_abbr(CPU), you will probably need to fuck with different code:
+ }
+
+ figure {
+ figcaption {
+ code {-~/board/hx20/board.h}
+ }
+ pre {= m4_fmt_code(fn-lock-1.diff.gsp) }
+ }
+
+ figure {
+ figcaption {
+ code {-~/board/hx20/keyboard-customization.c}
+ }
+ pre {= m4_fmt_code(fn-lock-2.diff.gsp) }
+ }
+
+ p {-
+ As you can see, toggling the capslock m4_abbr(LED) is as simple as
+ invoking @code{-gpio_set_level()}. Not only that, but disabling its
+ functionality with the capslock key is as easy as undefining the
+ @code{-CONFIG_CAPSLOCK_SUPPORT} macro. Figuring out if the function key
+ is locked is also really easy. The @code{-Fn_key} global variable is a
+ bit-field containing information pertaining to the function key, and we
+ also conveniently already have the @code{-FN_LOCKED} constant defined
+ that we can bitwise-AND with @code{-Fn_key} to check the locked state!
+ }
+
+ p {-
+ We also setup some hooks with the @code{-DECLARE_HOOK()} macro. These
+ just ensure that we are behaving properly on system resume and -suspend.
+ }
+
+ h2 #hybrid {-The Hybrid Key}
+ p {-
+ Wouldn’t it be cool if a physical key could represent two keys at the
+ same time? I thought so too. Like all Emacs users, I suffer from a
+ distinct lack of easily-accessible modifier keys. I need escape because
+ I use Vim bindings; I need left-control because all the Emacs bindings
+ use it; I need super for my window-managers’ bindings; I need left-alt
+ so I can type characters that don’t come on a standard American keyboard
+ (such as @em{-ß}, @em{-€}, and @em{-é}), and now I have a problem. All
+ my modifiers are taken, but Emacs still needs a meta key to work!
+ }
+
+ figure {
+ figcaption {-
+ @cite{-Workflow} by Randall Munroe
+ }
+ img alt="XKCD Comic 1172" src="1172.png" {}
+ }
+
+ p {-
+ What will I ever do‽ Well thanks to Framework making the m4_abbr(EC)
+ open-source, and conveniently giving me a file called
+ @code{-keyboard_customization.c}, I’m going to take two keys and stick
+ them in one! The basic premise is this: the capslock key is arguably
+ the easiest modifier key to hit, and it’s currently bound to the escape
+ key on my system. This is inefficient though, because nobody makes
+ key-bindings that chord the escape-key with another key;
+ chords @x-ref{-1} are always done with a modifier like control, and
+ Emacs is no different. So my plan was to make it so that the capslock
+ key when used on its own mimics an escape-key, while instead mimicking
+ the left-control-key when used in a chord with another key.
+ }
+
+ p {-
+ It took me a little longer this time to figure out how to implement what
+ I wanted since the code isn’t as clear, but it was still a surprisingly
+ easy feature to patch into the m4_abbr(EC)! I basically just updated
+ the scancode table, swapping out the capslock scancode for my own random
+ one that I called @code{-SCANCODE_CTRL_ESC}. I then created a new
+ function called @code{-try_ctrl_esc()} which is called in the on-keyup
+ and -down callback function. The @code{-try_ctrl_esc()} function
+ handles all of the logic as you can see in the following diff; it’s
+ basically just a state machine:
+ }
+
+ aside {
+ p data-ref="1" {-
+ If you’re confused by what I mean by a ‘key-chord’, I am simply
+ referring to pressing multiple keys in conjunction, such as when you
+ press ‘@kbd{-Ctrl + C}’ to copy text.
+ }
+ }
+
+ figure {
+ figcaption {
+ code {-~/board/hx20/keyboard_customization.c}
+ }
+ pre {= m4_fmt_code(hybrid.diff.gsp) }
+ }
+
+ p {-
+ One thing that’s good to take note of is what I return from
+ @code{-try_ctrl_esc()}. The general pattern for handling a keyup or
+ -down event is to stick the following code into
+ @code{-keyboard_scancode_callback()}:
+ }
+
+ figure {
+ figcaption {-
+ @code{-keyboard_scancode_callback()} in
+ @code{-~/board/hx20/keyboard_customization.c}
+ }
+ pre {= m4_fmt_code(kbd-sc-cb.c.gsp) }
+ }
+
+ p {-
+ In @code{-my_handler_function()} (or whatever you decide to name it),
+ you attempt to handle the event. If you don’t want to handle a
+ particular event and instead want to pass it on to the next handler, you
+ need to return @code{-EC_SUCCESS}. If you managed to successfully
+ handle the event though, then you need to return an error such as
+ @code{-EC_ERROR_UNIMPLEMENTED}. It’s pretty stupid and makes very
+ little sense from a naming perspective, but oh well…
+ }
+
+ h2 #next {-What’s Next?}
+ p {-
+ m4_abbr(RGB) m4_abbr(LED)s maybe.
+ }
+ }
+
+ hr{}
+
+ footer { m4_footer }
+ }
+}
diff --git a/src/blog/fw-ec/kbd-sc-cb.c.gsp b/src/blog/fw-ec/kbd-sc-cb.c.gsp
new file mode 100644
index 0000000..31524de
--- /dev/null
+++ b/src/blog/fw-ec/kbd-sc-cb.c.gsp
@@ -0,0 +1,6 @@
+@span .c-cmt {-/* ‘make_code’ is the scancode. ‘pressed’ is a boolean that is true if this is a}
+ @span .c-cmt {-keydown event, and false if it’s a keyup. */}
+
+r = @span .c-fn {-my_handler_function}(make_code, pressed);
+@span .c-kw {-if} (r != @span .c-pp {-EC_SUCCESS})
+ @span .c-kw {-return} r;
diff --git a/src/blog/fw-ec/led.diff.gsp b/src/blog/fw-ec/led.diff.gsp
new file mode 100644
index 0000000..ac7642f
--- /dev/null
+++ b/src/blog/fw-ec/led.diff.gsp
@@ -0,0 +1,32 @@
+@span .diff-meta {-diff --git a/board/hx20/led.c b/board/hx20/led.c}
+@span .diff-meta {-index a4dc4564e..dacf73fda 100644}
+@span .diff-meta {---- a/board/hx20/led.c}
+@span .diff-meta {-+++ b/board/hx20/led.c}
+@span .diff-loc {-\@\@ -283,22 +283,22 \@\@ static void led_set_power(void)}
+ /* don’t light up when at lid close */
+ if (!lid_is_open()) {
+ set_pwr_led_color(PWM_LED2, -1);
+@span .diff-del {-- enable_pwr_breath(PWM_LED2, EC_LED_COLOR_WHITE, breath_led_length, 0);}
+@span .diff-ins {-+ enable_pwr_breath(PWM_LED2, EC_LED_COLOR_GREEN, breath_led_length, 0);}
+ return;
+ \}
+
+ if (chipset_in_state(CHIPSET_STATE_ANY_SUSPEND))
+@span .diff-del {-- enable_pwr_breath(PWM_LED2, EC_LED_COLOR_WHITE, breath_led_length, 1);}
+@span .diff-ins {-+ enable_pwr_breath(PWM_LED2, EC_LED_COLOR_GREEN, breath_led_length, 1);}
+ else
+@span .diff-del {-- enable_pwr_breath(PWM_LED2, EC_LED_COLOR_WHITE, breath_led_length, 0);}
+@span .diff-ins {-+ enable_pwr_breath(PWM_LED2, EC_LED_COLOR_GREEN, breath_led_length, 0);}
+
+ if (chipset_in_state(CHIPSET_STATE_ON) | power_button_enable) {
+ if (charge_prevent_power_on(0))
+ set_pwr_led_color(PWM_LED2, (power_tick %
+ LED_TICKS_PER_CYCLE < LED_ON_TICKS) ?
+@span .diff-del {-- EC_LED_COLOR_WHITE : -1);}
+@span .diff-ins {-+ EC_LED_COLOR_GREEN : -1);}
+ else
+@span .diff-del {-- set_pwr_led_color(PWM_LED2, EC_LED_COLOR_WHITE);}
+@span .diff-ins {-+ set_pwr_led_color(PWM_LED2, EC_LED_COLOR_GREEN);}
+ \} else
+ set_pwr_led_color(PWM_LED2, -1);
+ \}