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

98
kernel/gmmos/hidkeys.c Normal file
View file

@ -0,0 +1,98 @@
// SPDX-License-Identifier: GPL-2.0-or-later
//
// Boot-layout keyboard reports to keys, for GMMOS's USB and I2C keyboards.
//
// usb_hid.c's keyboard path with the console, /dev/input, the lock and key
// repeat taken out: what is left is edge detection and a table. US layout, as
// the live USB path is.
#include "core/types.h"
#include "core/defs.h"
#include "dev/kbd.h"
#include "gmmos/gmmos.h"
#define MOD_CTRL 0x11
#define MOD_SHIFT 0x22
static const uchar plain[0x39] = {
0, 0, 0, 0,
'a','b','c','d','e','f','g','h','i','j','k','l','m',
'n','o','p','q','r','s','t','u','v','w','x','y','z',
'1','2','3','4','5','6','7','8','9','0',
'\n', 0x1B, '\b', '\t', ' ',
'-','=','[',']','\\','#',';','\'','`',',','.','/',
};
static const uchar shifted[0x39] = {
0, 0, 0, 0,
'A','B','C','D','E','F','G','H','I','J','K','L','M',
'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
'!','@','#','$','%','^','&','*','(',')',
'\n', 0x1B, '\b', '\t', ' ',
'_','+','{','}','|','~',':','"','~','<','>','?',
};
static int
special(uchar u)
{
switch (u) {
case 0x4A: return KBD_HOME;
case 0x4B: return KBD_PGUP;
case 0x4C: return KBD_DEL;
case 0x4D: return KBD_END;
case 0x4E: return KBD_PGDN;
case 0x4F: return KBD_RT;
case 0x50: return KBD_LF;
case 0x51: return KBD_DN;
case 0x52: return KBD_UP;
case 0x56: return '-'; // keypad minus and plus: the QR size keys
case 0x57: return '+';
case 0x58: return '\n'; // keypad Enter
}
return 0;
}
static int
was_down(const uchar *rep, uchar u)
{
for (int i = 2; i < 8; i++)
if (rep[i] == u)
return 1;
return 0;
}
void
gmmos_hid_report(struct gmmos_hidkeys *k, const uchar *boot)
{
uchar mods = boot[0];
for (int i = 2; i < 8; i++) {
uchar u = boot[i];
int c;
if (u < 4 || was_down(k->prev, u))
continue;
if (u < 0x39)
c = (mods & MOD_SHIFT) ? shifted[u] : plain[u];
else
c = special(u);
if (c == 0)
continue;
if ((mods & MOD_CTRL) && c < KBD_SPECIAL) {
if (c >= 'a' && c <= 'z') c = c - 'a' + 1;
else if (c >= 'A' && c <= 'Z') c = c - 'A' + 1;
else continue;
}
if (k->qt - k->qh < (int)NELEM(k->q))
k->q[k->qt++ % NELEM(k->q)] = c;
}
memmove(k->prev, boot, 8);
}
int
gmmos_hid_next(struct gmmos_hidkeys *k)
{
if (k->qh == k->qt)
return 0;
return k->q[k->qh++ % NELEM(k->q)];
}