# libScePad technical debt ### Additional callable exports - [Additional callable exports](../../../core/libs/prx/libScePad/InventoryExports.cpp) - 13 entries present in both version-labelled images are import-resolution declarations only. Neither label independently authenticates retail firmware provenance. These NIDs are absent from the pinned public 3.20 catalogue. Parameter lists, return types and behavior are unverified; parameterless `int` declarations are placeholders, not verified ABI contracts. Every entry throws through `NotImplemented_nid_no_patch`. Unidentified names use literal NID aliases. No runtime functionality is implemented. Data exports require separate layout and ownership analysis. Identified candidate names match their NIDs in the [public symbol database](https://github.com/zecoxao/sce_symbols/blob/2883963a0a514ba6e77407a08ef4730a65e88254/aerolib.csv) or [supplemental catalog](https://github.com/claimore22/ps5rs/blob/2304be5131221bae0dac24b9767cabffda33f747/data/nids.csv). | Name | NID | | --- | --- | | `Unknown` | `1YXygubV1Gc` | | `Unknown` | `3LNwlXW4f54` | | `Unknown` | `7xA+hFtvBCA` | | `Unknown` | `KY0hSB+Uyfo` | | `Unknown` | `Ql4q5ePNaw0` | | `Unknown` | `UeUUvNOgXKU` | | `Unknown` | `XFqNcPu1meI` | | `Unknown` | `eqldkyw7GAo` | | `Unknown` | `ickjfjk9okM` | | `Unknown` | `qJgegDoE0g8` | | `Unknown` | `r2S7Nuicg8s` | | `Unknown` | `wMvV6XbeFd0` | | `Unknown` | `ybhL4IoyGZA` | ### Silent stubs - [scePadEnableExtensionPort](../../../core/libs/prx/libScePad/Export.cpp) returns success without changing extension-port state. The boolean argument is recovered; connected-device behavior is not modeled. - [scePadSetLightBarBaseBrightness, scePadDisableTriggerEffect](../../../core/libs/prx/libScePad/Export.cpp) (libScePad) - return success for known handles without changing hardware states. `scePadIsLightBarBaseBrightnessControllable` reports 1 while the modifier is a no-op. ### Unknown function info - [libScePad profile and device-setting exports](../../../core/libs/prx/libScePad/Export.cpp) - profile getters, tuning, saved settings, USB state, shared output and virtual-device setting arguments are recovered. Hunt and Leonardo reset each consume only a handle; physical VR USB status consumes only an output pointer. Remote settings output is 64 bytes and license-controller information is 1224 bytes. Kernel ioctl payload fields remain incomplete. - [libScePad report and tracking exports](../../../core/libs/prx/libScePad/Export.cpp) - read, extended-read, tracker, UI, VR-controller and report argument registers are recovered. Feature reports use a byte report ID and 64-bit byte count, capped at 64. VR trigger effects consume a 56-byte record; the dual-controller call uses two handles and a mask with records at offsets 8 and 64. Remaining payload field layouts use incomplete declarations, including extended samples and kernel-owned extension reports. - [scePadUnknown_n3kSX62fgNo](../../../core/libs/prx/libScePad/Export.cpp) (libScePad, NID `n3kSX62fgNo`) - the name is unknown, and the 0 returned after `scePadInit` is inferred, not measured. In the OS 10.01 system module the function takes no arguments, returns `0x80920005` before `scePadInit`, and otherwise sends a per-process value of 1 to ShellCore over Mbus, returning `0x809200ff` if that call fails and 0 if it succeeds, with or without an open handle. The #3177 probe measured `0x809200ff` in a process that is not a game; a game process is assumed to get 0. The ShellCore setting it changes is unknown and not modelled - [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 port slot. One title (PPSA04354) disassembled for this entry calls it once (0xead26b), only when a change bit of its own is set, with a 32-bit value read through a pointer and 0 or 1 taken from the 0x4 bit of a flags value, and ignores the result. The call does not show the threshold or the default. - [PadQueueLegacyAudioHaptics, PadClearLegacyAudioHaptics](../../../core/libs/prx/libScePad/src/PadState.cpp) (libScePad) - PadQueueLegacyAudioHaptics and PadClearLegacyAudioHaptics route legacy audio haptics only to port 0; multi-port queueing is not modelled - [scePadGetControllerInformation](../../../core/libs/prx/libScePad/Export.cpp) (libScePad) - scePadGetControllerInformation reports connectedCount = 1 and connected = true on every port, except that port 0 reports its connection state under ANYPS5_PAD_PORT0_STATE=controller; behaviour across multiple open controller handles is not measured on hardware - [scePadGetExtControllerInformation](../../../core/libs/prx/libScePad/Export.cpp) (libScePad) - on a standard-port handle it returns `NOT_PERMITTED` (0x80920101) and leaves the buffer as it is. Halo CE Universal (PPSA99500) [measured](https://github.com/thelinkin3000/halo-ce-universal/blob/377459f9655971a2f59c09e192c5220042121e6f/port/ps5/probe/results/pad-probe-run2.txt#L2-L29) that answer on firmware 13.59 for two connected DualSenses opened by the title, in three runs, with its [probe](https://github.com/thelinkin3000/halo-ce-universal/blob/377459f9655971a2f59c09e192c5220042121e6f/port/ps5/probe/pad/main.c#L263-L268) zeroing the buffer first. The probe logged only bytes 28 to 47, which stayed zero, so whether the console writes any of the buffer is not known. The special port (type 2) still answers 0 with 0x2c zeroed bytes, which is not measured, and so are the order of the handle and null checks and the answer on a console that grants the permission. - [scePadReadState and scePadRead for port 0 while it is withdrawn](../../../core/libs/prx/libScePad/src/PadState.cpp) (libScePad) - under ANYPS5_PAD_PORT0_STATE=controller a port 0 without a controller reads zeroed data (buttons, sticks, triggers and touch zero, orientation identity) with connected false, and scePadRead returns one entry. The shape follows [shadPS4's pad.cpp](https://github.com/shadps4-emu/shadPS4/blob/1d8004a22feb0d5cc58828bac066018e80b6d73f/src/core/libraries/pad/pad.cpp#L369-L374) at commit 1d8004a22feb0d5cc58828bac066018e80b6d73f. What the console returns for a removed controller (zeroed, neutral or an error code) and the connected_count it reports are not measured. - [scePadOpen and scePadOpenExt](../../../core/libs/prx/libScePad/Export.cpp) (libScePad) - the special port (type 2) opens a handle per user (`PAD_SPECIAL_HANDLE` + slot, 16 slots for the console's 16 accounts, a 17th user gets the unknown-user code 0x809b0081) that every pad call accepts: reads give the rest record (sticks 0x80, orientation w 1, acceleration y 1, `connected` false), information is zeroed, extended information has device class -1, setters succeed without effect. Not measured: the console's own handle values (fresh per open), a PS5, and the calls the PS4 Pro survey (firmware 10.71, no special controller) did not cover; it measured open, `ALREADY_OPENED`, `scePadGetHandle`, both reads, both informations, the five setters above, close, and that two logged-in users get independent handles. `scePadOpenExt` returns `DEVICE_NOT_CONNECTED` (0x80920007) for special ports, unmeasured; PPSA01317 skips a user on any negative result. `scePadOpenExt` throws for other port types - [scePadOpen, scePadGetHandle, scePadRead and scePadReadState for the remote control port](../../../core/libs/prx/libScePad/Export.cpp) (libScePad) - whether a console without a media remote opens the system user's remote control port (type 16), returns `DEVICE_NOT_CONNECTED` or fills other fields is not measured. The host has no remote, so the port opens its own handle (`PAD_REMOTE_HANDLE`) that reads one zeroed entry with no buttons and `connected` false; the other pad calls reject it with `INVALID_HANDLE`. SDL's PS5 video driver maps this port's buttons to keys, so a remote that read the DualSense turned Cross into Return (Raptor PPSA94002). - [scePadOpen](../../../core/libs/prx/libScePad/Export.cpp) (libScePad) - types 3 and 4 return `INVALID_ARG` for a valid user as a compatibility fallback. The application-info gate and successful VR handles are not modelled. On PS5 firmware 13.40, a closed gate returns `INVALID_ARG` before user and index checks. With the gate open, PPSA01317 opened both types without connected VR controllers, with invalid user and index returning 0x809b0001 and 0x809b0003 ([evidence](https://github.com/boykopovar/AnyPS5/pull/10935#issuecomment-6408526250)). The fallback checks the user first. The relation to `attribute3` needs confirmation. A firmware 13.60 payload passed the type check but failed to open a port (0x809b0081). Of 21 calls in ten titles, 15 use type 0, three type 2 and three a dynamic type. All use index 0 and null param. - [scePadOpen argument observations](../../../core/libs/prx/libScePad/Export.cpp) - the 13.60 payload observed invalid types 1, 5, 6, 255, -1 and type 16 for a non-system user rejected before user validation. User -1 returned 0x809b0001 on types 0, 2, 3 and 4, and index 1 on type 0. A valid user with index 1 returned 0x809b0003. Index 1 for types 3 and 4 and type 16 for the system user were not measured. Of the type 2 calls above, PPSA01494, PPSA30839 and PPSA31162 each have one. PPSA18194 and PPSA25286 have the dynamic calls. - [scePadVrControllerRead](../../../core/libs/prx/libScePad/Export.cpp) - the handle, output pointer and count arguments and the 104-byte output layout are recovered, but touch-value semantics and kernel report production are not measured, so the returned sample and the success conditions are unknown; the export still throws. - [scePadVrControllerReadState](../../../core/libs/prx/libScePad/Export.cpp) - the 104-byte output layout is recovered, including buttons, stick, triggers, touch fields, motion, connection state and timestamp. Touch-value semantics and kernel report production remain incomplete; the export still throws. - [scePadVrControllerReadCombinedState](../../../core/libs/prx/libScePad/Export.cpp) - the two handle arguments and 128-byte output are recovered; output field semantics remain incomplete. - [scePadParseUniqueDataLeonardo and the DualShock 4 queries](../../../core/libs/prx/libScePad/Export.cpp) (libScePad) - like the other pad calls, they reject the handle opened on the remote port (type 16) with `INVALID_HANDLE` (see the remote control port entry), while firmware 13.42 checks the port type stored with each handle. The behaviour comes from firmware 13.42's libScePad.sprx, read from disassembly and compared by running the firmware functions natively on random handle tables, not measured on a console. The answers follow the firmware for the one DualSense (`054c:0ce6`) reported here: scePadGetMotionTimerUnit, scePadGetMotionSensorPosition and scePadGetSphereRadius return data only for DualShock 4 models (`05c4`, `0bb2`), scePadGetBluetoothAddress only for `03d5`, `05c4`, `0bb2` and `0c5e`, and scePadParseUniqueDataLeonardo only for the Access controller (`0e5f`). - [scePadSetTriggerEffect](../../../core/libs/prx/libScePad/Export.cpp) (libScePad) - only the commands the trigger mask selects are checked: a selected command with a mode above 6 returns `INVALID_ARG`, an unselected one is ignored whatever it holds, and a mask bit above 0x2 returns `INVALID_ARG`. Quake (PPSA01880) and Quake II (PPSA09477) pass mask 0x2 with the left command uninitialised. Not measured on a console, including whether modes above 6 are rejected. - [scePadSetVibrationMode](../../../core/libs/prx/libScePad/Export.cpp) (libScePad) - modes 1 to 3 and 5 are accepted and stored. On a PS5 (firmware 13.60) the call returns `0x80920005` before `scePadInit`, then rejects a mode of 0 or below with `INVALID_ARG` before it checks the handle, and returns `INVALID_HANDLE` for a bad handle with any higher mode; whether an open handle accepts modes above 3 was not measured, since the payload could not open a pad; 5 is accepted because PPSA25286 passes it on its open handle at start-up; the meanings of modes 3 and 5 are unknown (PPSA21480 calls it with 3 right after `scePadOpen` and aborts on failure; [SharpProspero](https://github.com/SvenGDK/SharpProspero/blob/main/src/SharpProspero/Interop/Pad/Pad.cs) names only 1 and 2). The stored mode has no other effect - [scePadIsRemoteController](../../../core/libs/prx/libScePad/Export.cpp) (libScePad) - the name hashes to NID `fCWdlnmB1Ks`; the signature `(int handle, bool* remote)` comes from PPSA16064, which zeroes a byte, passes its address after `scePadGetControllerInformation` and ignores the result. The error codes follow the other pad calls. Controllers are local devices, so the answer is always false - [scePadIsDS4Connected, scePadIsBlasterConnected and scePadIsMoveConnected](../../../core/libs/prx/libScePad/Export.cpp) (libScePad) - the `bool (int handle)` signatures are recovered; the library reports one DualSense to every title (see Touchpad resolution below), so no DualShock 4, Blaster or Move controller is ever behind a handle and each call answers false for any handle. The console's answer for an invalid handle is not measured - [scePadGetParticularMode, scePadGetControllerBusType, scePadGetJackState, scePadIsControllerUpdateRequired and scePadGetContainerIdInformation](../../../core/libs/prx/libScePad/Export.cpp) (libScePad) - the console's answers are not measured; signatures, the 0x2004-byte container record and the bus values (USB 1, Bluetooth 2) come from [duaLib](https://github.com/WujekFoliarz/duaLib/blob/master/src/include/duaLib.h), which reimplements the PC `libScePad.dll`. The emulated pad reports Bluetooth, no headset (state 0), no update required and an empty container id (duaLib fills it on Windows only). A special handle and a disconnected port answer `DEVICE_NOT_CONNECTED`, as in duaLib. `scePadSetParticularMode` stores its argument for the getter and nothing else: duaLib uses it to expose the Share and PS buttons in reads, which is not modelled. The null-pointer check before the handle check follows the library's other pad queries, not duaLib - [scePadIsSupportedAudioFunction, scePadSetAudioOutPath and scePadSetVolumeGain](../../../core/libs/prx/libScePad/Export.cpp) (libScePad) - the console's answers are not measured; signatures, the 4-byte gain record (speaker, headset, padding, microphone) and the path values 0 to 3 (stereo headset, mono-left headset, mono-left headset and speaker, speaker only) come from [duaLib](https://github.com/WujekFoliarz/duaLib/blob/master/src/include/duaLib.h). A path above 4 is rejected, 4 included, as in duaLib's [check](https://github.com/WujekFoliarz/duaLib/blob/master/src/source/duaLib.cpp), and what 4 means is unknown; duaLib's gain range test can never fail, so none is applied. Path and gain are only kept per port in `PadOutputState`: no host backend drives the controller speaker or headset or scales the gain to the hardware range. A special handle accepts the setters without effect - [scePadIsValidHandle](../../../core/libs/prx/libScePad/Export.cpp) (libScePad) - the `bool (int handle, int portType)` signature is recovered. Firmware 13.42's module, as BunnyFl ran it natively over a slot table he wrote ([comment](https://github.com/boykopovar/AnyPS5/pull/10880#issuecomment-6415854351); the driver emulated, the table not built by `scePadOpen`), answers 1 only when a slot holds the handle with exactly that port type, and 0 while not initialised. Here it is the same match on each open handle's type: 0 for a standard handle while its port is open, 2 for a special handle while its user's slot is open, 16 for the remote handle while the system user's remote port is open, and no match before `scePadInit`. `scePadOpen` opens no type-1 handle here, so no handle matches type 1. A closed standard handle is not valid, although the light bar, vibration and other setters keep accepting it - [scePadResetLightBarAll and scePadResetLightBarAllByPortType](../../../core/libs/prx/libScePad/Export.cpp) (libScePad) - the `(void)` and `(uint32_t portType)` signatures are recovered, and both follow firmware 13.42's module as BunnyFl ran it natively ([comment](https://github.com/boykopovar/AnyPS5/pull/10880#issuecomment-6415854351); the driver emulated, port type 1 unknown, the table not built by `scePadOpen`). By port type, any type but 0, 1 and 2 returns `INVALID_ARG` before the initialisation check (3, 4, 16 and -1 measured). Otherwise each open handle of that type is reset as `scePadResetLightBar` resets it, and the call returns `PAD_OK`, also before `scePadInit`, when it does nothing; `scePadResetLightBarAll` is type 0. In this model a special handle's reset has no effect, as special handles have no light bar, and `scePadOpen` opens no type-1 handle - [scePadSetVibrationForce](../../../core/libs/prx/libScePad/Export.cpp) (libScePad) - the `(int handle, const PadVibrationParam*)` signature is recovered. Firmware 13.42's module, as BunnyFl ran it natively ([comment](https://github.com/boykopovar/AnyPS5/pull/10880#issuecomment-6415854351); the driver emulated), returns `0x80920005` before `scePadInit`, even for a null `param`, then `INVALID_ARG` for a null `param`; otherwise it sends `scePadSetVibration`'s request with a force byte set, without looking the handle up, and returns the driver's answer. There is no pad driver here: a special handle returns `PAD_OK` without effect, as with `scePadSetVibration`, and a standard handle sets its pad port's motors whether or not it is still open. A handle with no pad port throws, as the driver's answer for it is not measured. In this model the force byte has no effect, as there is no system vibration-off setting to override (`scePadSetVibrationMode` only stores its mode) - [scePadSetAngularVelocityBiasCorrectionState](../../../core/libs/prx/libScePad/Export.cpp) (libScePad) - inferred signature `(int handle, bool enabled)` follows `scePadSetTiltCorrectionState` and `scePadSetAngularVelocityDeadbandState`; an invalid handle returns `PAD_ERROR_INVALID_HANDLE`, disabling is a no-op, and enabling throws because bias correction is not modelled - [scePadGetAccessibilityControllerState](../../../core/libs/prx/libScePad/Export.cpp) (libScePad) - the value a console reports for a DualSense is not measured; the emulated pad, which is not an Access controller, reports 0. The name hashes to NID `zBsgF0q8DIM`. In the OS 10.01 system module the `(int handle, uint32_t* state)` function returns `0x80920005` before `scePadInit`, then `INVALID_ARG` for a NULL `state` and `INVALID_HANDLE` for a bad handle, and otherwise asks the pad driver for a per-device value of the device behind the handle: 0 when no device is behind it, 1 when the driver has no answer, else the driver's value. What the values mean is unknown - [scePadGetControllerType](../../../core/libs/prx/libScePad/Export.cpp) (libScePad) - the value a console reports for a DualSense is not measured; the emulated pad reports `PAD_CONTROLLER_TYPE_DUAL_SENSE` (2), following [duaLib](https://github.com/WujekFoliarz/duaLib/blob/master/src/include/duaLib.h)'s `s_SceControllerType` enum where `UNKNOWN = 0` and `DUALSENSE = 2`; special handles report 0 (`UNKNOWN`). The signature `(int handle, int32_t* type)` follows duaLib, while the validation order (checking initialization, null pointer, then handle) follows the library's other pad queries; duaLib does not validate null pointers and returns `PAD_ERROR_DEVICE_NOT_CONNECTED` for an invalid pad. - [scePadDisableVibration, scePadIsLightBarBaseBrightnessControllable](../../../core/libs/prx/libScePad/Export.cpp) (libScePad) - `scePadDisableVibration(true)` stops active running motors on the port without disabling vibration for subsequent `scePadSetVibration` calls; `scePadIsLightBarBaseBrightnessControllable` reports 1 for standard DualSense handles and 0 for special handles while the modifier is a no-op. - [scePadGetDeviceInfo, GetCapability, GetVersionInfo, GetIdleCount, GetControllerIdleCount, GetActiveTime, SetPS4BcVibrationMode, GetInfoByPortType, GetExtensionUnitInfo, ReadHistory and OpenExt2](../../../core/libs/prx/libScePad/Export.cpp) (libScePad) - checks and their order follow @BunnyFl's [13.42 disassembly](https://github.com/boykopovar/AnyPS5/issues/15087#issuecomment-6580925450) of `libScePad.sprx` (SHA-256 `57eab7054e10d95ba0028dbd4808f94eb34c7663333a2b7ca9f68dc90cf62c60`), not a console. Past them each asks the driver, so it throws; a closed device fd counts as uninitialised. `GetInfoByPortType` checks a null output, then initialisation, then the type (0 or 2). `GetIdleCount` returns 0 before `scePadInit`, and `GetActiveTime` clears its output first. `ReadHistory`'s third argument is a byte size (0x960), and `OpenExt2(int32 userId, int32, const void*)` requires 0x10 in its unexplained middle argument. `GetExtensionUnitInfo`'s second-flag check (0x80920101) isn't modelled. - [scePadReadStateExt and scePadGetDeviceId](../../../core/libs/prx/libScePad/Export.cpp) (libScePad) - per the same [reading](https://github.com/boykopovar/AnyPS5/issues/15087#issuecomment-6580925450), `ReadStateExt` is `scePadReadState` with an extension flag: it runs this library's `ReadState` checks (handle, then output), then throws, since what the flag changes isn't known. The module checks a null output first, zero-fills the record, then checks initialisation before the handle; neither `ReadState` follows that order yet. `GetDeviceId(handle, int32*)` writes -1, then refuses an unknown handle with 0x80920003; the console then copies an id from the handle's slot (+0x18) whose source isn't known, so a known handle throws. - [libScePad internal data and device control](../../../core/libs/prx/libScePad/Export.cpp) - kernel-owned version, telemetry, Lotus-button and update payload fields remain unresolved. Lotus-button parameter units and the three blinking byte meanings are unknown. Port information occupies 152 bytes; history records occupy 72 bytes; Leonardo unique data occupies 24 bytes. Their complete field semantics remain unresolved. - [libScePad profile writes and virtual devices](../../../core/libs/prx/libScePad/Export.cpp) - profile writes take a handle, profile ID, profile pointer and a 32-bit result pointer; the profile payload direction and fields remain unresolved. Virtual-device creation takes an input record and an output ID pointer, whose width is not exposed by the wrapper. Component information copies 16 bytes; field meanings remain unknown. Virtual trigger state contains two 32-bit states and three control bytes, but the control semantics remain incomplete. ### Functional - [Touchpad resolution](../../../core/libs/prx/libScePad/include/PadState.hpp) (libScePad) - the library reports a DualSense to every title, so the controller information reports its touchpad, 1920 by 1080 at 44.86 pixels per cm, and the host controller's fingers and the keyboard touch contacts are placed in that range. [duaLib](https://github.com/WujekFoliarz/duaLib/blob/0b39f92261e2ff0e77eb0dac00943be6970e0dbf/src/source/duaLib.cpp#L847-L849) reports these values for a DualSense and 1920 by 943 at 44 for a DualShock 4, and the Linux kernel's [hid-playstation](https://github.com/torvalds/linux/blob/cd4f494ba535e848e2d299707d363de84e61a518/drivers/hid/hid-playstation.c#L177-L178) holds 1920 by 1080 against 1920 by 942 for the DualShock 4. A DualShock 4 on the host reports through the DualSense range too, so its last touchpad rows are never reached. A PS5 on firmware 13.40 reported 1920 by 1080 at 44.86 and stick dead zones of 13 to a retail title