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
65 lines
2.6 KiB
C
65 lines
2.6 KiB
C
#pragma once
|
|
|
|
#include "core/types.h"
|
|
|
|
// GMMOS -- Guru Meditation Micro OS. What runs after a panic.
|
|
//
|
|
// The PSOGM used to be the last thing the kernel did: a report, blinking
|
|
// keyboard lights, and a machine that needed its power button. GMMOS keeps the
|
|
// report and goes on living under it. The real kernel is dead and stays dead --
|
|
// every other processor is halted (see trap()), and nothing of it is called
|
|
// again that takes a lock, sleeps, allocates or waits for an interrupt. What
|
|
// GMMOS has instead is its own: the framebuffer, a clock read from the TSC, and
|
|
// keyboards it polls itself through micro drivers.
|
|
//
|
|
// A micro driver is a cut-down copy of a real one that does only what a
|
|
// keyboard needs. The real drivers run on interrupts, threads and locks, all of
|
|
// which belong to the kernel that just died.
|
|
//
|
|
// See kernel/gmmos/gmmos.c.
|
|
|
|
void gmmos_run(char *reason, addr_t *pcs, int npcs) __attribute__((noreturn));
|
|
|
|
// One keyboard GMMOS can read by polling.
|
|
struct gmmos_kbd {
|
|
const char *name;
|
|
int (*probe)(void); // nonzero if it is there and usable
|
|
// The next key, or 0 when there is none: a Unicode codepoint, or one of the
|
|
// KBD_* codes from include/dev/kbd.h for keys that are not characters.
|
|
int (*poll)(void);
|
|
void (*leds)(int on); // optional: all three lights on or off
|
|
};
|
|
|
|
extern const struct gmmos_kbd gmmos_ps2;
|
|
extern const struct gmmos_kbd gmmos_i2c;
|
|
|
|
// A USB or I2C keyboard report in the boot layout -- modifiers, a reserved
|
|
// byte, six usages -- turned into keys. A report is a state, not an event, so
|
|
// a key is a usage that was not in the previous one. kernel/gmmos/hidkeys.c.
|
|
struct gmmos_hidkeys {
|
|
uchar prev[8];
|
|
int q[16];
|
|
int qh, qt;
|
|
};
|
|
void gmmos_hid_report(struct gmmos_hidkeys *k, const uchar *boot);
|
|
int gmmos_hid_next(struct gmmos_hidkeys *k);
|
|
|
|
// I2C keyboards, as kernel/acpi/i2c_hid.c found them at boot. GMMOS cannot run
|
|
// ACPI to find them again, so the live driver hands over what it learnt: the
|
|
// DesignWare controller, the device's address, its input report size, the
|
|
// interrupt pin when there is one, and the parsed report descriptor.
|
|
struct gmmos_i2c_kbd {
|
|
volatile uint32 *regs;
|
|
int txdepth, rxdepth;
|
|
int addr;
|
|
uint32 maxin;
|
|
volatile uint32 *pin; // AMD GPIO pin register, or 0: poll blindly
|
|
int active_low;
|
|
void *hid;
|
|
};
|
|
int i2c_hid_keyboards(struct gmmos_i2c_kbd *out, int max);
|
|
|
|
// From kernel/core/panic.c: draw the report again, and where its closing
|
|
// lines are, which GMMOS writes its status and its keys into.
|
|
void psogm_repaint(void);
|
|
void psogm_footer(int *x, int *y, int *step);
|