using System.Runtime.InteropServices;
namespace XFESystem.NativeKernel;
// 8042 hardware port and bounded queue. Decoder is the same production source
// linked into the host regressions, with no injected event path in this driver.
public static unsafe class Ps2Input
{
const uint Capacity = 256, PollLimit = 100000;
static NativeInputReport* _reports;
static uint _head, _tail, _lost;
static Ps2DecodeState _decoder;
static uint _buttons;
public static uint ReadyBits;
public static ulong HardwareBytes, QueuedReports;
static bool Write(ushort port, byte value)
{
for (uint poll = 0; poll < PollLimit; poll++)
{
if ((Native.In8(0x64) & 2) == 0) { Native.Out8(port, value); return true; }
Native.Pause();
}
return false;
}
static bool Read(out byte value, bool mouse)
{
value = 0;
for (uint poll = 0; poll < PollLimit; poll++)
{
byte status = Native.In8(0x64);
if (status == 255) return false;
if ((status & 1) != 0)
{
byte data = Native.In8(0x60);
if (((status & 32) != 0) == mouse) { value = data; return true; }
Decode((status & 32) != 0, data);
}
Native.Pause();
}
return false;
}
static bool Device(byte value, bool mouse)
{
for (uint attempt = 0; attempt < 3; attempt++)
{
if (mouse && !Write(0x64, 0xd4)) return false;
if (!Write(0x60, value) || !Read(out byte ack, mouse)) return false;
if (ack == 0xfa) return true;
if (ack != 0xfe) return false;
}
return false;
}
public static void Initialize()
{
_reports = (NativeInputReport*)Native.Storage(10);
_head = _tail = _lost = 0; ReadyBits = 0;
_decoder = new Ps2DecodeState();
if (_reports == null || Native.In8(0x64) == 255) return;
if (!Write(0x64, 0xad) || !Write(0x64, 0xa7)) return;
for (uint i = 0; i < 64 && (Native.In8(0x64) & 1) != 0; i++) Native.In8(0x60);
if (!Write(0x64, 0x20) || !Read(out byte config, false)) return;
// Translation converts the keyboard's set 2 into set 1; IRQs stay masked
// because the independent LAPIC tick services both device queues.
config = (byte)((config | 0x40) & ~0x33);
if (!Write(0x64, 0x60) || !Write(0x60, config) || !Write(0x64, 0xae)) return;
if (Device(0xf5, false) && Device(0xf0, false) && Device(2, false) && Device(0xf4, false)) ReadyBits |= 1;
if (Write(0x64, 0xa8) && Device(0xf6, true) && Device(0xf4, true)) ReadyBits |= 2;
Serial.Write("XFE_INPUT_READY keyboard="); Serial.Number((ReadyBits & 1) != 0 ? 1UL : 0UL);
Serial.Write(" mouse="); Serial.Number((ReadyBits & 2) != 0 ? 1UL : 0UL); Serial.Line("");
}
static void Decode(bool mouse, byte value)
{
NativeInputReport report;
bool complete = mouse ? Ps2Decoder.DecodeMouse(ref _decoder, value, &report) : Ps2Decoder.DecodeKeyboard(ref _decoder, value, &report);
if (!complete) return;
if (mouse) _buttons = report.Buttons;
uint next = (_tail + 1) % Capacity;
if (next == _head)
{
_lost++; _head = _tail = 0;
Ps2Decoder.ResetKeyboard(ref _decoder); Ps2Decoder.ResetMouse(ref _decoder);
return;
}
_reports[_tail] = report; _tail = next; QueuedReports++;
}
public static void Poll()
{
if (_reports == null || ReadyBits == 0) return;
for (uint i = 0; i < 64; i++)
{
byte status = Native.In8(0x64);
if (status == 255 || (status & 1) == 0) return;
byte value = Native.In8(0x60); HardwareBytes++;
if ((status & 0xc0) != 0)
{
_lost++; _head = _tail = 0;
Ps2Decoder.ResetKeyboard(ref _decoder); Ps2Decoder.ResetMouse(ref _decoder);
continue;
}
bool mouse = (status & 32) != 0;
if ((ReadyBits & (mouse ? 2u : 1u)) != 0) Decode(mouse, value);
}
}
[UnmanagedCallersOnly(EntryPoint = "xfe_runtime_input_ready")]
public static int Ready() => (int)ReadyBits;
[UnmanagedCallersOnly(EntryPoint = "xfe_runtime_input_read")]
public static int ReadReport(NativeInputReport* output)
{
if (output == null || _reports == null) return 0;
ulong flags = Native.IrqSave();
if (_lost != 0)
{
*output = new NativeInputReport { Kind = 4, KeyCode = _lost, Buttons = _buttons };
_lost = 0; Native.IrqRestore(flags); return 1;
}
if (_head == _tail) { Native.IrqRestore(flags); return 0; }
*output = _reports[_head]; _head = (_head + 1) % Capacity;
Native.IrqRestore(flags); return 1;
}
}
using System.Runtime.InteropServices;
namespace XFESystem.NativeKernel;
// 8042 hardware port and bounded queue. Decoder is the same production source
// linked into the host regressions, with no injected event path in this driver.
public static unsafe class Ps2Input
{
const uint Capacity = 256, PollLimit = 100000;
static NativeInputReport* _reports;
static uint _head, _tail, _lost;
static Ps2DecodeState _decoder;
static uint _buttons;
public static uint ReadyBits;
public static ulong HardwareBytes, QueuedReports;
static bool Write(ushort port, byte value)
{
for (uint poll = 0; poll < PollLimit; poll++)
{
if ((Native.In8(0x64) & 2) == 0) { Native.Out8(port, value); return true; }
Native.Pause();
}
return false;
}
static bool Read(out byte value, bool mouse)
{
value = 0;
for (uint poll = 0; poll < PollLimit; poll++)
{
byte status = Native.In8(0x64);
if (status == 255) return false;
if ((status & 1) != 0)
{
byte data = Native.In8(0x60);
if (((status & 32) != 0) == mouse) { value = data; return true; }
Decode((status & 32) != 0, data);
}
Native.Pause();
}
return false;
}
static bool Device(byte value, bool mouse)
{
for (uint attempt = 0; attempt < 3; attempt++)
{
if (mouse && !Write(0x64, 0xd4)) return false;
if (!Write(0x60, value) || !Read(out byte ack, mouse)) return false;
if (ack == 0xfa) return true;
if (ack != 0xfe) return false;
}
return false;
}
public static void Initialize()
{
_reports = (NativeInputReport*)Native.Storage(10);
_head = _tail = _lost = 0; ReadyBits = 0;
_decoder = new Ps2DecodeState();
if (_reports == null || Native.In8(0x64) == 255) return;
if (!Write(0x64, 0xad) || !Write(0x64, 0xa7)) return;
for (uint i = 0; i < 64 && (Native.In8(0x64) & 1) != 0; i++) Native.In8(0x60);
if (!Write(0x64, 0x20) || !Read(out byte config, false)) return;
// Translation converts the keyboard's set 2 into set 1; IRQs stay masked
// because the independent LAPIC tick services both device queues.
config = (byte)((config | 0x40) & ~0x33);
if (!Write(0x64, 0x60) || !Write(0x60, config) || !Write(0x64, 0xae)) return;
if (Device(0xf5, false) && Device(0xf0, false) && Device(2, false) && Device(0xf4, false)) ReadyBits |= 1;
if (Write(0x64, 0xa8) && Device(0xf6, true) && Device(0xf4, true)) ReadyBits |= 2;
Serial.Write("XFE_INPUT_READY keyboard="); Serial.Number((ReadyBits & 1) != 0 ? 1UL : 0UL);
Serial.Write(" mouse="); Serial.Number((ReadyBits & 2) != 0 ? 1UL : 0UL); Serial.Line("");
}
static void Decode(bool mouse, byte value)
{
NativeInputReport report;
bool complete = mouse ? Ps2Decoder.DecodeMouse(ref _decoder, value, &report) : Ps2Decoder.DecodeKeyboard(ref _decoder, value, &report);
if (!complete) return;
if (mouse) _buttons = report.Buttons;
uint next = (_tail + 1) % Capacity;
if (next == _head)
{
_lost++; _head = _tail = 0;
Ps2Decoder.ResetKeyboard(ref _decoder); Ps2Decoder.ResetMouse(ref _decoder);
return;
}
_reports[_tail] = report; _tail = next; QueuedReports++;
}
public static void Poll()
{
if (_reports == null || ReadyBits == 0) return;
for (uint i = 0; i < 64; i++)
{
byte status = Native.In8(0x64);
if (status == 255 || (status & 1) == 0) return;
byte value = Native.In8(0x60); HardwareBytes++;
if ((status & 0xc0) != 0)
{
_lost++; _head = _tail = 0;
Ps2Decoder.ResetKeyboard(ref _decoder); Ps2Decoder.ResetMouse(ref _decoder);
continue;
}
bool mouse = (status & 32) != 0;
if ((ReadyBits & (mouse ? 2u : 1u)) != 0) Decode(mouse, value);
}
}
[UnmanagedCallersOnly(EntryPoint = "xfe_runtime_input_ready")]
public static int Ready() => (int)ReadyBits;
[UnmanagedCallersOnly(EntryPoint = "xfe_runtime_input_read")]
public static int ReadReport(NativeInputReport* output)
{
if (output == null || _reports == null) return 0;
ulong flags = Native.IrqSave();
if (_lost != 0)
{
*output = new NativeInputReport { Kind = 4, KeyCode = _lost, Buttons = _buttons };
_lost = 0; Native.IrqRestore(flags); return 1;
}
if (_head == _tail) { Native.IrqRestore(flags); return 0; }
*output = _reports[_head]; _head = (_head + 1) % Capacity;
Native.IrqRestore(flags); return 1;
}
}