D316 - Porthole input injection via Ghostpad Virtual Device Interface (VDI)
decided - 2026-09-03
The Problem
Porthole receives 24-byte PPAD packets on TCP port 9806.
To control the console and games:
- The payload must inject these inputs into the PS5 input subsystem.
- Standard
scePad*APIs (scePadReadState) are consumers of input, not providers. - The platform's Virtual Device subsystem (
libScePad) is the underlying mechanism used by the OS for Remote Play and virtual gamepads.
Decision
Ghostpad Virtual Device Interface (VDI):
- Use
libScePad's virtual device calls (scePadVirtualDeviceAddDevice,scePadVirtualDeviceInsertData, andscePadVirtualDeviceDeleteDevice). - Self-resolve these symbols via the live kernel dispatch table walk (D277/D300).
- Lazily register a virtual DualSense device (type 3) upon receiving the first input record for a given slot (0..3).
- Use
Input Freshness Policy (State, Not Events):
- Controller input is a continuous state, not an event stream.
- Maintain per-slot sequence tracking
(
last_sequence). - If an input record arrives with a sequence number less than or equal
to
last_sequence, discard it immediately. This prevents replaying stale joystick positions or button presses caused by network jitter. - Slot tracking is strictly independent: activity on slot 0 never affects the sequence freshness of slot 1.
Packet Translation:
- The 24-byte
PPADrecord layout was designed to match the Ghostpad pad structure starting at byte offset 8 (uint32_t buttons, 4 stick bytes, 2 trigger bytes). porthole_pad_applypacks these fields into the 16-byte virtual pad input packet and dispatches it viascePadVirtualDeviceInsertData.
- The 24-byte
Consequences
- Full controller input support on port 9806 with sub-millisecond dispatch.
- Zero libc and zero dynamic memory allocations in the input path.
- Host selftests verify sequence freshness, monotonic ordering, and multi-slot tracking without needing hardware.