GMMOS: I2C keyboards, and every keyboard at once

The second micro driver: i2c_hid.c with everything but reading a
keyboard's input reports taken out. No ACPI -- AML cannot run on a dead
kernel -- so the live driver hands over what it found at boot
(i2c_hid_keyboards): the DesignWare controller, the address, the report
size, the AMD GPIO pin if there is one, and the parsed report descriptor.
No power commands, no reset, a read-only transfer.

usb_hid.c's report-protocol rewrite is split out as hid_boot_report(),
which does nothing but rewrite, and kernel/gmmos/hidkeys.c turns boot
reports into keys for this and the USB micro drivers to come.

GMMOS now probes every micro driver and polls all that answer.

Not run: QEMU has no DesignWare I2C, and the laptops at hand have PS/2
keyboards.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
This commit is contained in:
Nexoniarz 2026-10-25 01:15:50 +02:00
commit c6d90e69fa
8 changed files with 387 additions and 17 deletions

View file

@ -47,7 +47,30 @@ static addr_t *pcs;
static int npcs;
static int sw, sh, cw, ch;
static const struct gmmos_kbd *kbd;
// Every micro driver, in the order they are tried. All that answer are
// polled: a laptop has its own keyboard and maybe a USB one on the side.
static const struct gmmos_kbd *const drivers[] = { &gmmos_ps2, &gmmos_i2c };
static const struct gmmos_kbd *kbds[NELEM(drivers)];
static int nkbd;
static int
poll_keys(void)
{
for (int i = 0; i < nkbd; i++) {
int k = kbds[i]->poll();
if (k)
return k;
}
return 0;
}
static void
set_lights(int on)
{
for (int i = 0; i < nkbd; i++)
if (kbds[i]->leds)
kbds[i]->leds(on);
}
enum { MAIN, QRPAGES, LOG, TERM };
static int mode = MAIN;
@ -493,6 +516,7 @@ cmd_help(void)
tline("pci PCI devices");
tline("mem ADDR [LEN] bytes at a kernel address; both in hex (80, up to 400)");
tline("uptime how long it ran, and how long since");
tline("keyboards which keyboards GMMOS is reading");
tline("clear empty this screen");
tline("restart restart the machine");
tline("poweroff power it off");
@ -763,6 +787,10 @@ run(void)
else if (streq(w, "pci")) cmd_pci();
else if (streq(w, "mem")) cmd_mem(arg);
else if (streq(w, "uptime")) cmd_uptime();
else if (streq(w, "keyboards")) {
for (int i = 0; i < nkbd; i++)
tline(kbds[i]->name);
}
else if (streq(w, "clear")) tn = 0;
else if (streq(w, "restart") || streq(w, "reboot")) restart();
else if (streq(w, "poweroff")) {
@ -829,7 +857,7 @@ draw_status(void)
sb_putc(&sb, ':');
sb_putc(&sb, (char)('0' + left % 60 / 10));
sb_putc(&sb, (char)('0' + left % 10));
sb_puts(&sb, kbd ? ". Any key keeps it on." : ".");
sb_puts(&sb, nkbd ? ". Any key keeps it on." : ".");
} else {
sb_puts(&sb, "Staying on. Nothing here is lost until it restarts.");
}
@ -837,7 +865,7 @@ draw_status(void)
textn(x, y + step, sbz(&sb), (sw * 2 / 3 - x) / cw, PSOGM_DIM);
gfx_fill_rect(x, y + step * 3, sw - x, ch + 2, PSOGM_BG);
if (kbd)
if (nkbd)
textn(x, y + step * 3,
"Space log as QR L read the log T terminal R restart P power off",
(sw - x) / cw, PSOGM_FG);
@ -961,8 +989,9 @@ gmmos_run(char *r, addr_t *p, int n)
rows = (sh - my * 2) / ch;
log_snapshot();
if (gmmos_ps2.probe())
kbd = &gmmos_ps2;
for (int i = 0; i < (int)NELEM(drivers); i++)
if (drivers[i]->probe())
kbds[nkbd++] = drivers[i];
tline("GMMOS, the Guru Meditation Micro OS. The kernel is dead; this is what");
tline("runs after it. help lists the commands.");
draw_status();
@ -971,10 +1000,10 @@ gmmos_run(char *r, addr_t *p, int n)
int lights = 0, keyed = 0;
for (;;) {
int k = kbd ? kbd->poll() : 0;
int k = poll_keys();
if (k) {
if (!keyed && kbd->leds) {
kbd->leds(0); // somebody is here: the lights have done their job
if (!keyed) {
set_lights(0); // somebody is here: the lights have done their job
lights = 0;
}
keyed = 1;
@ -1001,10 +1030,10 @@ gmmos_run(char *r, addr_t *p, int n)
}
// The lights until somebody presses a key, as panic_blink did: on a
// machine whose screen is black, they are all there is to say it died.
if (!keyed && kbd && kbd->leds && t - last_blink >= 333) {
if (!keyed && t - last_blink >= 333) {
last_blink = t;
lights = !lights;
kbd->leds(lights);
set_lights(lights);
}
if (!boot_verbose && !cancelled && t - entered_ms >= OFF_MS) {
acpi_poweroff_now();