Repository navigation
fix(libScePad): return measured status for unknown Pad NID - #5676
Conversation
|
CONTRIBUTING allows code comments only for technical debt, so the three comment lines in scePadUnknown_n3kSX62fgNo should move to the debt entry. That entry is the right place to record "firmware 13.60, before/after scePadInit, no argument pointers read or written", which is currently in the code. 0x80920005 and 0x809200ff look like the known pad error codes NOT_INITIALIZED and FATAL (the same values other PS4/PS5 projects use). Naming the constants PAD_ERROR_NOT_INITIALIZED / PAD_ERROR_FATAL instead of PAD_UNKNOWN_N3KSX62FGNO_BEFORE/AFTER_INIT would say what they mean, and the before-init value could be reused by other exports that check initialization. |
|
Additional title evidence for the controller-open limitation: Castlevania Dominus Collection (PPSA15645, 01.003.000) calls this import after opening a pad. On Windows with GCC 15.2, I built and tested the exact Pad change from 9e6dba8 on the frozen 0aa4cb1 base. Both Separately, read-only debugger observation of the original title using the baseline Pad runtime established this order:
I stopped before the unknown call rather than treating this as covered by the #3177 probe, where PadOpen failed. No return was substituted. This does not demonstrate title progress or correct input behavior, and it is not a current-main gameplay test. Correction to my initial wording: the behavioral tests used the new unpatched module, but the title observation loaded the old packaged module. The packaging check caught this; the observation therefore establishes the baseline open-controller state, not execution of this PR. A hardware measurement with a successfully opened controller would cover a state this title actually uses. The current measured scope is useful, but cannot yet establish the result or side effects for that state. Prepared with AI assistance. |
|
Moved the probe details from the code comments into |
|
Title evidence for this pull request: Raiden III x MIKADO MANIAX (PPSA13356), Windows 10 (19045), RTX 4080 SUPER, one 90 s run. Without a change to With this pull request (head With #5038 ( Test conditions: AI-assisted (Claude Code). |
5dd44a8 to
1c7a09d
Compare
|
Rebased onto current Validation on Linux:
The earlier focused CTest pass was on the previous revision; this rebase's runtime result is limited by the host CPU. |
|
Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.
|
|
The rebase's CTest run could not reach the assertions, so here is a runtime result for the current head (
One gap: the after-init assertion (GuestPad.cpp#L102-L104) runs inside
The change below returns the measured statuses while no handle is open and keeps throwing while one is. With it on diff against 1c7a09ddiff --git a/core/libs/prx/libScePad/Export.cpp b/core/libs/prx/libScePad/Export.cpp
index 802a25dc1..b2a61b864 100644
--- a/core/libs/prx/libScePad/Export.cpp
+++ b/core/libs/prx/libScePad/Export.cpp
@@ -315,6 +315,7 @@ int APS5_VABI scePadSetAngularVelocityBiasCorrectionState(int handle, bool enabl
APS5_EXPORT("n3kSX62fgNo", scePadUnknown_n3kSX62fgNo);
int APS5_VABI scePadUnknown_n3kSX62fgNo() {
+ if (g_opened) NotImplemented_nid_no_patch(__func__);
return g_initialized.load(std::memory_order_acquire) ? PAD_UNKNOWN_N3KSX62FGNO_AFTER_INIT : PAD_UNKNOWN_N3KSX62FGNO_BEFORE_INIT;
}
diff --git a/core/libs/tests/GuestPad.cpp b/core/libs/tests/GuestPad.cpp
index 37cd4f0ec..c7cdb0d1a 100644
--- a/core/libs/tests/GuestPad.cpp
+++ b/core/libs/tests/GuestPad.cpp
@@ -7,6 +7,8 @@
#include <cstdlib>
#include <filesystem>
#include <fstream>
+#include <stdexcept>
+#include <string>
#include <thread>
extern "C" {
@@ -29,6 +31,15 @@ int APS5_VABI scePadIsRemoteController(int, bool*);
static void Require(bool value) { if (!value) std::abort(); }
+static bool UnknownN3kNotImplemented() {
+ try {
+ scePadUnknown_n3kSX62fgNo();
+ } catch (const std::runtime_error& error) {
+ return std::string(error.what()) == "scePadUnknown_n3kSX62fgNo not implemented";
+ }
+ return false;
+}
+
static void CheckInputCommands() {
const auto path = std::filesystem::temp_directory_path() / ("anyps5-pad-" + std::to_string(std::chrono::steady_clock::now().time_since_epoch().count()));
struct Cleanup {
@@ -101,7 +112,7 @@ static float SettleOrientationW() {
static void CheckTiltCorrection(int handle) {
Require(scePadInit_nid_postfix() == 0);
- Require(scePadUnknown_n3kSX62fgNo() == static_cast<int>(0x809200ff));
+ Require(UnknownN3kNotImplemented());
PadInputState tilted;
tilted.hasMotion = true;
tilted.accel = {9.80665f, 0.0f, 0.0f};
@@ -243,6 +254,8 @@ static void CheckInjectedState(const std::filesystem::path& path) {
int main() {
CheckInputCommands();
Require(scePadUnknown_n3kSX62fgNo() == static_cast<int>(0x80920005));
+ Require(scePadInit_nid_postfix() == 0);
+ Require(scePadUnknown_n3kSX62fgNo() == static_cast<int>(0x809200ff));
const auto path = std::filesystem::temp_directory_path() / ("anyps5-pad-state-" + std::to_string(std::chrono::steady_clock::now().time_since_epoch().count()));
struct Cleanup {
std::filesystem::path path;
diff --git a/docs/dev/debt/libScePad.md b/docs/dev/debt/libScePad.md
index bec36f662..a851c5301 100644
--- a/docs/dev/debt/libScePad.md
+++ b/docs/dev/debt/libScePad.md
@@ -2,7 +2,7 @@
### Unknown function info
-- [scePadUnknown_n3kSX62fgNo](../../../core/libs/prx/libScePad/Export.cpp) (libScePad, NID `n3kSX62fgNo`) - firmware 13.60 returned `0x80920005` before `scePadInit` and `0x809200ff` after it in the #3177 probe; the tested call read or wrote no argument pointers. PPSA15645 calls the import after `scePadOpen`, but its return and side effects in that state are unknown. The NID name and signature are unknown, so the statuses are not named by presumed error meanings
+- [scePadUnknown_n3kSX62fgNo](../../../core/libs/prx/libScePad/Export.cpp) (libScePad, NID `n3kSX62fgNo`) - firmware 13.60 returned `0x80920005` before `scePadInit` and `0x809200ff` after it in the #3177 probe; the tested call read or wrote no argument pointers. PPSA15645 calls the import after `scePadOpen`; the probe's `scePadOpen` failed, so the return and side effects with a handle open are unknown and that state throws. The NID name and signature are unknown, so the statuses are not named by presumed error meanings
- [scePadSetAngularVelocityDeadbandState](../../../core/libs/prx/libScePad/src/PadState.cpp) (libScePad) - with the deadband on, each angular velocity axis whose magnitude is below 0.017453292 rad/s (1 degree per second) reads as 0, before the orientation is integrated; it starts off. Threshold, per-axis test and default follow [duaLib](https://github.com/WujekFoliarz/duaLib/blob/03bad1bea2a36561b520846776f2a07ced6773e0/src/source/duaLib.cpp#L44), which reimplements the PC `libScePad.dll`; the console's threshold is not measured, and the deadband is kept per library rather than per handle since one pad handle exists
- [scePadOpen and scePadOpenExt](../../../core/libs/prx/libScePad/Export.cpp) (libScePad) - special ports (type 2) return `DEVICE_NOT_CONNECTED` (0x80920007) because the host has no special controller, and `scePadGetHandle` has no handle for them; whether the console opens a handle and reports the device as disconnected later is unknown. scePadOpenExt handles only special ports. PPSA01317 passes a 16-byte param that names the device by vendor and product id (`b7 0e 04 0e ...` for 0x0eb7:0x0e04) and skips the user on any negative result. Other port types throw
- [scePadVrControllerReadState](../../../core/libs/prx/libScePad/Export.cpp) (libScePad, NID `iA-DdobUen8`) - the name hashes to the imported NID; the `(int handle, void* state)` signature follows [PS5VR](https://github.com/theghostonline/PS5VR/blob/0e408909ce7a39891a2e06eee3438d07a09e11e3/app/src/app_vr.c#L326-L369) (PPSA99177), which passes a PS VR2 Sense controller handle from `scePadOpen` type 3 or 4 and a 0x68-byte state it reads as buttons at 0, stick bytes at 4 and a connected byte at 0x40. The title calls it only after `sceHmd2Initialize` succeeds, which it does not here, so every call throws; the state layout is otherwise unknownThe trade-off: PPSA15645 keeps stopping at this call, and PPSA13356, which gets past it with this PR in @xXPBSXx's run (comment), would stop here again if it also calls it with a handle open. @xXPBSXx, would a run on AI-assisted: written with Claude Code; I checked the head's export and test against the #3177 probe and the PPSA15645 trace, and ran |
|
Please take @nikowolf123's change above: keep the measured statuses while no handle is open, and throw while one is. The #3177 probe never had an open handle, so |
1c7a09d to
46c0de1
Compare
|
I updated #5676 on current |
|
The latest head ( |
46c0de1 to
e35c62c
Compare
|
Rebased onto current |
What
Implements the measured behavior for libScePad NID
n3kSX62fgNo: it returns0x80920005beforescePadInitand0x809200ffafter initialization while no controller is open. A PS5 probe found no memory access through the tested argument values. The NID's name and signature remain unknown. Calls with an open controller remain unmeasured and throw rather than assuming the post-init status applies. This removes the observed startup abort without pretending the underlying API is understood. Resolves the measured portion of #3177.Tested
main2fab88d10.python3 tools/check_conventions.py --base 2fab88d10andgit diff --checkpass.guest_ppsa01530_exportstest only asserted that this export threw as an unimplemented stub. It is removed because this PR now implements the two measured return states;guest_padcovers the before-init, after-init/no-handle, and open-controller states.guest_pad_testsand the then-existingguest_ppsa01530_exports_tests. CTest stopped before assertions because this host's Xeon E5-1620 v2 lacks LZCNT, BMI1/2, MOVBE, AVX2 and FMA. I have not rerun the emulator tests on a compatible host after rebasing.Checklist
main; no other open PR implements the same functionsdocs/dev/debt/libScePad.md.mdfiles or images added to the repository