feat(usb): a USB keyboard -- a full one -- and no hang on a PC without PS/2
boards/BRINGUP.md A3 and S3, FABRIC-3 SXLI. A HID boot keyboard is configured (interrupt IN endpoint, SET_PROTOCOL boot) and its reports become the same Linux-keycode events as PS/2 and virtio (usb_kbd.c): the full layout -- F-keys, navigation block, arrows, Num Lock, keypad. The console treats Caps and Num Lock as toggles shown on the keyboard's lights, and the keypad as digits or navigation. While a USB keyboard runs, its event ring is serviced every tick, not once a second. Found on the way: with no i8042 (port 0x64 reads 0xFF) the kernel hung at boot in an endless drain -- a legacy-free PC would stop there. Detected and skipped now; drains bounded. QEMU, amd64 with the USB keyboard the only one: 1 2 + . on main keys and keypad, Caps Lock, Num Lock all right; aarch64/riscv64 configure it too. Acceptance on three ISAs unchanged; identities hot-plug. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
080b7012ba
commit
739cb9c163
+68
-1
@@ -50,6 +50,7 @@
|
||||
#include "starkernel/vm/stadium.h" /* task 3.8 -- stadium_conserved() evidence print */
|
||||
#include "block_subsystem.h"
|
||||
#include "word_source/include/keyboard_words.h"
|
||||
#include "starkernel/usb_kbd.h" /* usb_kbd_set_leds() -- the lock lights, A3 */
|
||||
#include "word_source/include/block_words.h"
|
||||
#include "word_registry.h"
|
||||
#include "freestanding/stdio.h"
|
||||
@@ -906,10 +907,53 @@ static const char sk_kbd_shifted[SK_KBD_TABLE_SIZE] = {
|
||||
#define SK_KEY_RIGHTSHIFT 54u
|
||||
#define SK_KEY_LEFTALT 56u
|
||||
#define SK_KEY_RIGHTALT 100u
|
||||
#define SK_KEY_CAPSLOCK 58u
|
||||
#define SK_KEY_NUMLOCK 69u
|
||||
#define SK_KEY_KPENTER 96u
|
||||
#define SK_KEY_KPSLASH 98u
|
||||
#define SK_KEY_102ND 86u
|
||||
|
||||
static int g_kbd_shift_down; /* zero-initialized (BSS) */
|
||||
static int g_kbd_alt_down;
|
||||
|
||||
/* A full-size keyboard (Captain Bob, 2026-10-14: "include caps lock,
|
||||
* numlock, keypad and arrow"). Caps Lock and Num Lock are toggles, held
|
||||
* here for every keyboard alike and shown on a USB keyboard's lights
|
||||
* (usb_kbd_set_leds()). Num Lock starts on, as a PC's firmware usually
|
||||
* leaves it. Caps Lock acts on letters only; Shift reverses it. */
|
||||
static int g_kbd_caps_lock;
|
||||
static int g_kbd_num_lock = 1;
|
||||
|
||||
static void sk_kbd_show_locks(void)
|
||||
{
|
||||
usb_kbd_set_leds((uint8_t)((g_kbd_num_lock ? USB_KBD_LED_NUM : 0) |
|
||||
(g_kbd_caps_lock ? USB_KBD_LED_CAPS : 0)));
|
||||
}
|
||||
|
||||
/* The keypad: what each key types. With Num Lock on, 0-9 and '.'; with it
|
||||
* off those are Home/arrows/PgUp/... -- navigation, which this REPL's
|
||||
* append/backspace editing has no use for, so they type nothing (as the
|
||||
* arrow keys do). / * - + always type; keypad Enter is Enter. */
|
||||
static int sk_kbd_keypad(uint16_t keycode)
|
||||
{
|
||||
switch (keycode) {
|
||||
case 55u: return '*';
|
||||
case 74u: return '-';
|
||||
case 78u: return '+';
|
||||
case SK_KEY_KPSLASH: return '/';
|
||||
case SK_KEY_KPENTER: return '\n';
|
||||
default: break;
|
||||
}
|
||||
if (!g_kbd_num_lock) return 0;
|
||||
switch (keycode) {
|
||||
case 71u: return '7'; case 72u: return '8'; case 73u: return '9';
|
||||
case 75u: return '4'; case 76u: return '5'; case 77u: return '6';
|
||||
case 79u: return '1'; case 80u: return '2'; case 81u: return '3';
|
||||
case 82u: return '0'; case 83u: return '.';
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Drains and translates one physically-typed key. Modifier state persists
|
||||
* across calls (a real keyboard's shift/alt state is global, not
|
||||
* per-line). Alt+TAB is intercepted here and drives the graphics/text
|
||||
@@ -932,6 +976,14 @@ static int sk_kbd_getc(void)
|
||||
}
|
||||
if (!pressed) continue; /* only act on press/repeat */
|
||||
|
||||
if (keycode == SK_KEY_CAPSLOCK) { g_kbd_caps_lock = !g_kbd_caps_lock; sk_kbd_show_locks(); continue; }
|
||||
if (keycode == SK_KEY_NUMLOCK) { g_kbd_num_lock = !g_kbd_num_lock; sk_kbd_show_locks(); continue; }
|
||||
{
|
||||
int k = sk_kbd_keypad(keycode);
|
||||
if (k) return k;
|
||||
}
|
||||
if (keycode == SK_KEY_102ND) return g_kbd_shift_down ? '|' : '\\';
|
||||
|
||||
if (keycode == SK_KEY_TAB) {
|
||||
if (g_kbd_alt_down) console_fb_toggle_graphics();
|
||||
continue; /* bare TAB: not mapped, same as arrows/F-keys */
|
||||
@@ -940,7 +992,10 @@ static int sk_kbd_getc(void)
|
||||
if (keycode == SK_KEY_BACKSPACE) return 0x7F;
|
||||
|
||||
if (keycode < SK_KBD_TABLE_SIZE) {
|
||||
char c = g_kbd_shift_down ? sk_kbd_shifted[keycode] : sk_kbd_unshifted[keycode];
|
||||
char lower = sk_kbd_unshifted[keycode];
|
||||
int shift = g_kbd_shift_down;
|
||||
if (lower >= 'a' && lower <= 'z' && g_kbd_caps_lock) shift = !shift;
|
||||
char c = shift ? sk_kbd_shifted[keycode] : lower;
|
||||
if (c) return (unsigned char)c;
|
||||
}
|
||||
/* unmapped keycode -- drop and keep draining */
|
||||
@@ -954,8 +1009,20 @@ static int sk_kbd_getc(void)
|
||||
* sk_console_key_available() (the standard dictionary's KEY/?TERMINAL, wired
|
||||
* through shim.c's getchar()) and sk_console_readline() (QUERY/EXPECT, wired
|
||||
* through shim.c's fgets()) alike. */
|
||||
static uint64_t g_kbd_poll_tick;
|
||||
|
||||
static int sk_console_getc_raw(void)
|
||||
{
|
||||
/* A USB keyboard's reports come in on the xHCI event ring: while one is
|
||||
* running, service the ring once per timer tick here, not only on the
|
||||
* once-a-second idle beat -- keys arrive at typing speed (A3). */
|
||||
if (xhci_keyboard_running()) {
|
||||
uint64_t t = heartbeat_ticks();
|
||||
if (t != g_kbd_poll_tick) {
|
||||
g_kbd_poll_tick = t;
|
||||
xhci_poll_events();
|
||||
}
|
||||
}
|
||||
int c = console_getc();
|
||||
if (c < 0) c = sk_kbd_getc(); /* FABRIC-0.md 4.4v: second source, same buffer */
|
||||
return c;
|
||||
|
||||
Reference in New Issue
Block a user