Files
LithosAnanke/v3/src/word_source/keyboard_words.c
T
Claude 16b9747d33 chore(license): the source headers name the Starship License 1.0 (SL-1.0), as LICENSE does [skip ci]
347 headers said "Licensed under the StarForth License, Version 1.0" -- a
shortening (Captain Bob, 2026-11-08: "License file SL I think I shortened
accidently"); LICENSE is, and has been since the first commit, the
Starship License 1.0 (SL-1.0, SPDX LicenseRef-Starship-1.0). 349 files,
566 occurrences, now "Starship License, Version 1.0 (SL-1.0)".

Left as they are, pending a ruling: docs/patent/ (the patent figures),
docs/formal/ (the citable volumes) and the generated reports under
docs/working/experiments/ (32 files). Comments and license text only:
the amd64 kernel builds, every changed script parses.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
2026-11-08 17:54:24 +00:00

196 lines
6.6 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
StarForth — Steady-State Virtual Machine Runtime
Copyright (c) 2023–2025 Robert A. James
All rights reserved.
Licensed under the Starship License, Version 1.0 (SL-1.0)
*/
/* keyboard_words.c — raw scancode-ring diagnostic word (FABRIC-0.md item
* 4.3.5). Kernel-only, amd64-only; no-op elsewhere. */
#include "include/keyboard_words.h"
#include "../../include/word_registry.h"
#if defined(__STARKERNEL__) && defined(ARCH_AMD64)
#include "starkernel/i8042.h"
#endif
#if defined(__STARKERNEL__) && (defined(ARCH_RISCV64) || defined(ARCH_AARCH64))
#include "starkernel/virtio_input.h"
#endif
#if defined(__STARKERNEL__)
#include "starkernel/console.h"
#include "starkernel/usb_kbd.h" /* usb_kbd_pop_event() -- A3 */
#endif
/* KBD-SCAN ( -- c -1 | 0 ) */
static void kbw_scan(VM *vm)
{
#if defined(__STARKERNEL__) && defined(ARCH_AMD64)
uint8_t sc;
if (i8042_pop_scancode(&sc)) {
vm_push(vm, (cell_t)sc);
vm_push(vm, -1);
} else {
vm_push(vm, 0);
}
#else
vm_push(vm, 0);
#endif
}
/* KBD-DEBUG ( -- isr_count spurious_count ): cheap standing diagnostic,
* not scaffolding -- confirms the interrupt path is alive (isr_count) and
* flags the failure mode item 4.3.5 found (a real IRQ misreported as
* spurious) without needing a live debugger. */
extern volatile uint32_t g_i8042_isr_count;
extern volatile uint32_t g_spurious_count;
static void kbw_debug(VM *vm)
{
#if defined(__STARKERNEL__) && defined(ARCH_AMD64)
vm_push(vm, (cell_t)g_i8042_isr_count);
vm_push(vm, (cell_t)g_spurious_count);
#else
vm_push(vm, 0);
vm_push(vm, 0);
#endif
}
/* VKBD-EVENT ( -- code value -1 | 0 ): item 4.3.5c (riscv64) / 4.3.5e
* (aarch64) virtio-input. Pop one decoded EV_KEY event off the
* interrupt-fed ring buffer. Pushes code and value and -1 (true) if one
* was available, or just 0 (false) if the buffer was empty. Distinct word
* from KBD-SCAN rather than a shared one: different device, different
* event shape (Linux-style code/value pair vs. a raw XT scancode byte) --
* convergence onto one interface is item 4.3.5f's explicit job, not this
* one's. */
static void kbw_vevent(VM *vm)
{
#if defined(__STARKERNEL__) && (defined(ARCH_RISCV64) || defined(ARCH_AARCH64))
uint16_t code;
uint32_t value;
if (virtio_input_pop_event(&code, &value)) {
vm_push(vm, (cell_t)code);
vm_push(vm, (cell_t)value);
vm_push(vm, -1);
} else {
vm_push(vm, 0);
}
#else
vm_push(vm, 0);
#endif
}
/* VKBD-DEBUG ( -- isr_count ): standing diagnostic, same shape as
* KBD-DEBUG -- confirms the virtio-input interrupt path is alive. */
extern volatile uint32_t g_virtio_input_isr_count;
static void kbw_vdebug(VM *vm)
{
#if defined(__STARKERNEL__) && (defined(ARCH_RISCV64) || defined(ARCH_AARCH64))
vm_push(vm, (cell_t)g_virtio_input_isr_count);
#else
vm_push(vm, 0);
#endif
}
/* KEY-EVENT ( -- keycode pressed -1 | 0 ): item 4.3.5f convergence
* checkpoint. One shared shape across all three architectures instead of
* KBD-SCAN's raw XT scancode byte or VKBD-EVENT's Linux code/value pair.
* keycode is the Linux input keycode namespace (linux/input-event-codes.h);
* pressed is 1 (press) or 0 (release).
*
* amd64 needs a real translation, not an invented one: XT Set-1's make
* code for a key and Linux's keycode for that same key are the *same
* number*, confirmed against this build host's own
* /usr/include/linux/input-event-codes.h and against this tree's own
* live-observed values (item 4.3.5's done note: 'a' -> 30, 'b' -> 48,
* matching KEY_A=30/KEY_B=48 exactly) -- not a coincidence, a documented
* historical property of how the Linux input keycode numbering was
* originally defined around the AT/XT scancode set. Break codes set XT's
* bit 7 (make|0x80) rather than carrying a separate press/release field,
* so `keycode = sc & 0x7F, pressed = !(sc & 0x80)` is the whole
* translation for the entire non-extended key range. Extended
* (0xE0-prefixed) scancodes are not decoded here -- this checkpoint needs
* one shared shape proven live per architecture, not full keyboard
* coverage; that belongs to the REPL wiring item (M8) this checkpoint
* unblocks.
*
* riscv64/aarch64 need no translation at all -- virtio-input's `code`
* field already lives in the same Linux keycode namespace; `value` is
* mapped 1:1 except autorepeat (value=2), folded into "still pressed"
* here since this checkpoint's shape only distinguishes press/release. */
/* FABRIC-0.md item 4.4v: shared C-level implementation, so the REPL
* keyboard bridge (repl.c) and the KEY-EVENT FORTH word below poll the
* exact same converged event stream rather than each re-deriving the
* per-arch translation kbw_key_event's own doc comment already explains
* (XT Set-1 make code == Linux keycode for the non-extended range; break
* codes set bit 7 instead of carrying a separate field). */
int sk_key_event_poll(uint16_t *keycode, int *pressed)
{
#if defined(__STARKERNEL__)
/* A USB boot keyboard, on any architecture (2026-10-14,
* boards/BRINGUP.md A3): already in Linux keycodes (usb_kbd.c). */
if (usb_kbd_pop_event(keycode, pressed)) return 1;
#endif
#if defined(__STARKERNEL__) && defined(ARCH_AMD64)
uint8_t sc;
if (i8042_pop_scancode(&sc)) {
*keycode = (uint16_t)(sc & 0x7Fu);
*pressed = (sc & 0x80u) ? 0 : 1;
return 1;
}
return 0;
#elif defined(__STARKERNEL__) && (defined(ARCH_RISCV64) || defined(ARCH_AARCH64))
uint16_t code;
uint32_t value;
if (virtio_input_pop_event(&code, &value)) {
*keycode = code;
*pressed = (value == 0u) ? 0 : 1;
return 1;
}
return 0;
#else
(void)keycode; (void)pressed;
return 0;
#endif
}
static void kbw_key_event(VM *vm)
{
uint16_t keycode;
int pressed;
if (sk_key_event_poll(&keycode, &pressed)) {
vm_push(vm, (cell_t)keycode);
vm_push(vm, (cell_t)pressed);
vm_push(vm, -1);
} else {
vm_push(vm, 0);
}
}
/* ALT+TAB ( -- ): FABRIC-0.md item 4.4y-revised. Programmatic equivalent of
* the physical Alt+TAB interception (repl.c's sk_kbd_getc()) -- both call
* console_fb_toggle_graphics(), so there is exactly one state-machine
* transition, invoked two ways. */
static void kbw_alt_tab(VM *vm)
{
(void)vm;
#if defined(__STARKERNEL__)
console_fb_toggle_graphics();
#endif
}
void register_keyboard_words(VM *vm)
{
register_word(vm, "KBD-SCAN", kbw_scan);
register_word(vm, "KBD-DEBUG", kbw_debug);
register_word(vm, "VKBD-EVENT", kbw_vevent);
register_word(vm, "VKBD-DEBUG", kbw_vdebug);
register_word(vm, "KEY-EVENT", kbw_key_event);
register_word(vm, "ALT+TAB", kbw_alt_tab);
}