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
98 lines
2.4 KiB
C
98 lines
2.4 KiB
C
// 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)];
|
|
}
|