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;
static uint _ps2ReadyBits;
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, uint limit = PollLimit)
{
value = 0;
ulong deadline = limit > PollLimit && MonotonicClock.Ready ? MonotonicClock.Nanoseconds() + 1000000000 : 0;
for (uint poll = 0; poll < limit; poll++)
{
if (deadline != 0 && MonotonicClock.Nanoseconds() >= deadline) return false;
byte status = Native.In8(0x64);
if (status == 255) return false;
if ((status & 1) != 0)
{
byte data = Native.In8(0x60);
if ((status & 0xc0) != 0) return false;
if (((status & 32) != 0) == mouse) { value = data; return true; }
bool otherMouse = (status & 32) != 0;
if ((ReadyBits & (otherMouse ? 2u : 1u)) != 0) Decode(otherMouse, 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;
}
static bool ResetMouseDevice()
{
// F6 does not reset an IntelliMouse's packet ID. A successful FF BAT
// and ID0 reply are required before selecting the standard fallback.
if (!Device(0xff, true) || !Read(out byte bat, true, PollLimit * 1000) || bat != 0xaa ||
!Read(out byte id, true) || id != 0) return false;
return Ps2Decoder.SetMouseDeviceId(ref _decoder, id);
}
static bool SampleRate(byte rate) => Device(0xf3, true) && Device(rate, true);
static bool InitializeMouse()
{
if (!Write(0x64, 0xa8) || !ResetMouseDevice()) return false;
bool identified = SampleRate(200) && SampleRate(100) && SampleRate(80) &&
Device(0xf2, true) && Read(out byte id, true) && Ps2Decoder.SetMouseDeviceId(ref _decoder, id);
// A failed/unknown reply leaves the hardware protocol uncertain. Never
// parse a four-byte device as three bytes just by changing software.
if (!identified && !ResetMouseDevice()) return false;
if (!Device(0xea, true) || !Device(0xf4, true)) return false;
ReadyBits |= 2;
if (_decoder.MouseDeviceId == 3) ReadyBits |= 4;
return true;
}
public static void Initialize()
{
// The LAPIC poller must not consume ACK/BAT bytes while the keyboard
// is already enabled and the mouse is negotiating its packet format.
ulong flags = Native.IrqSave();
InitializeDevices();
_ps2ReadyBits = ReadyBits;
Native.IrqRestore(flags);
}
static void InitializeDevices()
{
_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;
InitializeMouse();
Serial.Write("XFE_INPUT_READY keyboard="); Serial.Number((ReadyBits & 1) != 0 ? 1UL : 0UL);
Serial.Write(" mouse="); Serial.Number((ReadyBits & 2) != 0 ? 1UL : 0UL);
Serial.Write(" wheel="); Serial.Number((ReadyBits & 4) != 0 ? 1UL : 0UL);
Serial.Write(" id="); Serial.Number(_decoder.MouseDeviceId); 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;
Enqueue(report);
}
// Both physical backends share this ABI and queue. xHCI calls it from its
// native worker; IRQ masking excludes the PS/2 tick producer and consumer.
public static void Enqueue(NativeInputReport report)
{
ulong flags = Native.IrqSave();
if (_reports == null) { Native.IrqRestore(flags); return; }
if (report.Kind == Ps2Decoder.Pointer) _buttons = report.Buttons;
uint next = (_tail + 1) % Capacity;
if (next == _head)
{
_lost++; _head = _tail = 0;
Ps2Decoder.ResetKeyboard(ref _decoder); Ps2Decoder.ResetMouse(ref _decoder);
Native.IrqRestore(flags); return;
}
_reports[_tail] = report; _tail = next; QueuedReports++;
Native.IrqRestore(flags);
}
public static void InputLost()
{
ulong flags = Native.IrqSave(); _lost++; _head = _tail = 0; _buttons = 0;
Native.IrqRestore(flags);
}
public static void SetUsbCapabilities(uint bits)
{
ulong flags = Native.IrqSave(); ReadyBits = _ps2ReadyBits | (bits & 7); Native.IrqRestore(flags);
}
public static void Poll()
{
if (_reports == null || _ps2ReadyBits == 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 ((_ps2ReadyBits & (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;
static uint _ps2ReadyBits;
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, uint limit = PollLimit)
{
value = 0;
ulong deadline = limit > PollLimit && MonotonicClock.Ready ? MonotonicClock.Nanoseconds() + 1000000000 : 0;
for (uint poll = 0; poll < limit; poll++)
{
if (deadline != 0 && MonotonicClock.Nanoseconds() >= deadline) return false;
byte status = Native.In8(0x64);
if (status == 255) return false;
if ((status & 1) != 0)
{
byte data = Native.In8(0x60);
if ((status & 0xc0) != 0) return false;
if (((status & 32) != 0) == mouse) { value = data; return true; }
bool otherMouse = (status & 32) != 0;
if ((ReadyBits & (otherMouse ? 2u : 1u)) != 0) Decode(otherMouse, 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;
}
static bool ResetMouseDevice()
{
// F6 does not reset an IntelliMouse's packet ID. A successful FF BAT
// and ID0 reply are required before selecting the standard fallback.
if (!Device(0xff, true) || !Read(out byte bat, true, PollLimit * 1000) || bat != 0xaa ||
!Read(out byte id, true) || id != 0) return false;
return Ps2Decoder.SetMouseDeviceId(ref _decoder, id);
}
static bool SampleRate(byte rate) => Device(0xf3, true) && Device(rate, true);
static bool InitializeMouse()
{
if (!Write(0x64, 0xa8) || !ResetMouseDevice()) return false;
bool identified = SampleRate(200) && SampleRate(100) && SampleRate(80) &&
Device(0xf2, true) && Read(out byte id, true) && Ps2Decoder.SetMouseDeviceId(ref _decoder, id);
// A failed/unknown reply leaves the hardware protocol uncertain. Never
// parse a four-byte device as three bytes just by changing software.
if (!identified && !ResetMouseDevice()) return false;
if (!Device(0xea, true) || !Device(0xf4, true)) return false;
ReadyBits |= 2;
if (_decoder.MouseDeviceId == 3) ReadyBits |= 4;
return true;
}
public static void Initialize()
{
// The LAPIC poller must not consume ACK/BAT bytes while the keyboard
// is already enabled and the mouse is negotiating its packet format.
ulong flags = Native.IrqSave();
InitializeDevices();
_ps2ReadyBits = ReadyBits;
Native.IrqRestore(flags);
}
static void InitializeDevices()
{
_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;
InitializeMouse();
Serial.Write("XFE_INPUT_READY keyboard="); Serial.Number((ReadyBits & 1) != 0 ? 1UL : 0UL);
Serial.Write(" mouse="); Serial.Number((ReadyBits & 2) != 0 ? 1UL : 0UL);
Serial.Write(" wheel="); Serial.Number((ReadyBits & 4) != 0 ? 1UL : 0UL);
Serial.Write(" id="); Serial.Number(_decoder.MouseDeviceId); 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;
Enqueue(report);
}
// Both physical backends share this ABI and queue. xHCI calls it from its
// native worker; IRQ masking excludes the PS/2 tick producer and consumer.
public static void Enqueue(NativeInputReport report)
{
ulong flags = Native.IrqSave();
if (_reports == null) { Native.IrqRestore(flags); return; }
if (report.Kind == Ps2Decoder.Pointer) _buttons = report.Buttons;
uint next = (_tail + 1) % Capacity;
if (next == _head)
{
_lost++; _head = _tail = 0;
Ps2Decoder.ResetKeyboard(ref _decoder); Ps2Decoder.ResetMouse(ref _decoder);
Native.IrqRestore(flags); return;
}
_reports[_tail] = report; _tail = next; QueuedReports++;
Native.IrqRestore(flags);
}
public static void InputLost()
{
ulong flags = Native.IrqSave(); _lost++; _head = _tail = 0; _buttons = 0;
Native.IrqRestore(flags);
}
public static void SetUsbCapabilities(uint bits)
{
ulong flags = Native.IrqSave(); ReadyBits = _ps2ReadyBits | (bits & 7); Native.IrqRestore(flags);
}
public static void Poll()
{
if (_reports == null || _ps2ReadyBits == 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 ((_ps2ReadyBits & (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;
}
}