mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-26 02:11:36 -04:00
Remove Tomba legacy hybrid controller path
This commit is contained in:
@@ -6,7 +6,13 @@ against the in-tree Beetle/Mednafen oracle
|
||||
`frontio.cpp`, `input/dualshock.cpp`, `input/gamepad.cpp`, `input/memcard.cpp`)
|
||||
and nocash psx-spx "Controllers and Memory Cards".
|
||||
|
||||
READ-ONLY research. No code was modified. Citations use `file:line`.
|
||||
Historical read-only research; citations use the line numbers from that audit.
|
||||
|
||||
> **Status 2026-07-26:** Tomba now offers explicit Analog / D-Pad modes instead
|
||||
> of Hybrid. The Tomba-only `g_pad_legacy_cfg` protocol fork, its game-config
|
||||
> key, debug command, and helper script have been removed. References to them
|
||||
> below document the retired implementation and are not descriptions of the
|
||||
> current runtime.
|
||||
|
||||
---
|
||||
|
||||
@@ -245,7 +251,10 @@ every title — which is exactly what the LEGACY comment predicted, letting the
|
||||
|
||||
## 4. Prioritized fix list (player-visible impact first)
|
||||
|
||||
> **STATUS 2026-06-27 (branch wt/tomba2-axis5-controller):** Fixes 1, 2, 3 IMPLEMENTED
|
||||
> **STATUS 2026-07-26:** Fixes 1, 2, 3 are implemented. Fix 4 is also complete:
|
||||
> Tomba no longer uses Hybrid, and the legacy pad-config branch has been removed.
|
||||
>
|
||||
> **Prior status 2026-06-27 (branch wt/tomba2-axis5-controller):** Fixes 1, 2, 3 IMPLEMENTED
|
||||
> in sio.c (0x43 live frame; 0x45 live analog byte; 0x44 analog-mode-lock + hybrid-flip
|
||||
> lock gate), transcribed from dualshock.cpp. Validated no-regression on Tomba 2
|
||||
> (digital pad, pad 0xFFFF at rest, boots). These are gated to the MODERN SM and leave
|
||||
@@ -275,10 +284,10 @@ every title — which is exactly what the LEGACY comment predicted, letting the
|
||||
game-locked mode) — mirror `dualshock.cpp:203,714-725`. Prevents the hybrid
|
||||
heuristic from fighting games that pin DualShock.
|
||||
|
||||
4. **[P1] Retire `g_pad_legacy_cfg` once 1–3 land** (sio.c:665-717, the LEGACY
|
||||
block + `legacy_pad_config` game.toml key + Tomba's opt-in). The completeness
|
||||
path the file itself mandates: one correct SM for all titles, no per-game
|
||||
compat branch. Validate Tomba on the modern SM after 1–3.
|
||||
4. **[DONE 2026-07-26] Retire `g_pad_legacy_cfg`.** Tomba now exposes only
|
||||
explicit Analog / D-Pad modes, so there is no live type flip to accommodate.
|
||||
The flag, legacy SIO branches, config key, debug command, helper script, and
|
||||
Tomba opt-in were removed. All titles use the modern DualShock state machine.
|
||||
|
||||
5. **[P2] Echo-back `0x4D` rumble map** (D7). Even with no rumble output,
|
||||
echo the previous `rumble_magic[]` bytes (`dualshock.cpp:993-1024`) so a game
|
||||
@@ -321,8 +330,8 @@ the always-on rings), drive the same input, then diff:
|
||||
does), then deflect the stick. `pad_status.analog` must NOT change while
|
||||
locked; cross-check Beetle stays in its locked mode across the same input.
|
||||
|
||||
- **Fix 4 (retire legacy):** run Tomba on the modern SM with `legacy_pad_config`
|
||||
off. `pad_status` at rest = `0xFFFF` both slots, no disconnect blips; menu
|
||||
- **Fix 4 (retire legacy):** run Tomba in both explicit Analog and D-Pad modes
|
||||
on the modern SM. `pad_status` at rest = `0xFFFF` both slots, no disconnect blips; menu
|
||||
responsive; in-game d-pad↔stick transitions produce no phantom dash/unpause.
|
||||
Diff a 600-byte `sio_trace` window vs Beetle for the same navigation — RX
|
||||
streams should match transaction-for-transaction (allowing the D3 stick-order
|
||||
|
||||
@@ -159,9 +159,11 @@ bug**, not timing.
|
||||
now arms the cycle-paced ack scheduler, BAUD+ACK=1258 cyc, like the card
|
||||
path). This was the cause of the load=4 Tomba 2 boot wedge (accurate CPU
|
||||
exposed access-paced pad timing). See WEDGE_load4_shell_rootcause.md.
|
||||
- DONE 2026-07-26: Tomba now offers explicit Analog / D-Pad modes; the
|
||||
Tomba-only legacy pad-config fork and its debug/config surface were removed.
|
||||
Every title now uses the modern DualShock config state machine.
|
||||
- TODO (axis5 Fix-6 / "1.0e-e2"): fully remove the pad fast-path so pad+card
|
||||
share the unified shifter path; D4/D8 config-mode `0x43`/`0x45` semantics
|
||||
(hybrid-pad fix, retire g_pad_legacy_cfg) still open.
|
||||
share the unified shifter path.
|
||||
- [ ] **GPU**: GP0/GP1 command set, rasterization rules (top-left fill, dithering,
|
||||
semi-transparency modes, mask bit, texture windows, blending), VRAM-as-texture —
|
||||
cross-ref DuckStation gpu_*, Beetle gpu.cpp, GPU test ROMs; validate by VRAM diff.
|
||||
@@ -224,8 +226,9 @@ overlap the cycle axis or each other (different files), so they parallelize.
|
||||
must transmit the LIVE button frame (like `0x42`) + use the trailing byte to toggle
|
||||
config; we send all-zeros → active-low → "all buttons pressed" phantom input every
|
||||
`0x43` frame. P0: `0x45` status must report the LIVE analog/digital mode, not always
|
||||
analog-ON (→ frame-length misparse after a flip). Fixing both lets the
|
||||
`g_pad_legacy_cfg` Tomba hack be DELETED. P1: analog-mode lock (`0x44`); P2: `0x4D`
|
||||
analog-ON (→ frame-length misparse after a flip). Both were fixed, and the
|
||||
Tomba legacy fork was deleted 2026-07-26 when Tomba moved to explicit
|
||||
Analog / D-Pad modes. P1: analog-mode lock (`0x44`); P2: `0x4D`
|
||||
rumble echo + cycle-paced pad ACK. Validate: `sio_trace` diff on `0x43`/`0x45`.
|
||||
- **`accuracy/axis5_gpu.md`.** P1: dithering ENTIRELY MISSING in both renderers (decoded
|
||||
but never forwarded) — largest systematic banding divergence. P2: SW rasterizer uses
|
||||
|
||||
@@ -454,13 +454,6 @@ static RuntimeConfig parse_runtime_block(const toml::value& cfg, const fs::path&
|
||||
rt.deadzone = static_cast<int>(n);
|
||||
rt.has_deadzone = true;
|
||||
}
|
||||
// LEGACY per-game pad-config opt-in (default modern). Tomba sets this so
|
||||
// its launcher Hybrid mode's analog<->digital type flip doesn't make libpad
|
||||
// manufacture a disconnect; no other title is affected. Full history and
|
||||
// the removal plan live in psxrecomp runtime/src/sio.c (g_pad_legacy_cfg).
|
||||
if (ct.contains("legacy_pad_config")) {
|
||||
rt.legacy_pad_config = toml::find<bool>(ct, "legacy_pad_config");
|
||||
}
|
||||
}
|
||||
|
||||
return rt;
|
||||
|
||||
@@ -372,16 +372,6 @@ struct RuntimeConfig {
|
||||
bool has_deadzone = false;
|
||||
int deadzone = 0;
|
||||
|
||||
// legacy_pad_config: per-game pad-protocol compatibility opt-in. false (default)
|
||||
// = the modern DualShock config state machine (proper 0x43 enter/exit, config id
|
||||
// 0xF3 only while in config) — required by MMX6 and the correct default for every
|
||||
// title. true = the pre-98aa688 behaviour (config commands always answer 0xF3, no
|
||||
// enter/exit tracking). Only Tomba opts in: its libpad re-detect — triggered by the
|
||||
// launcher Hybrid mode's analog<->digital type flip — manufactures a 1-frame "pad
|
||||
// unplugged" under the modern SM (menu unpause / phantom input). The legacy answers
|
||||
// make that re-detect benign. Scoped per-game; no other title's behaviour changes.
|
||||
// Wired to sio_set_legacy_cfg(); see sio.c g_pad_legacy_cfg.
|
||||
bool legacy_pad_config = false;
|
||||
};
|
||||
|
||||
// One entry from [[recompiler.bios_vectors]].
|
||||
|
||||
@@ -231,11 +231,6 @@ typedef struct {
|
||||
|
||||
uint32_t sio_get_irq_ring(const SioIrqEntry **buf_out, int *write_idx_out);
|
||||
|
||||
/* Phantom-input regression A/B instrument: select pre/post-98aa688 pad config
|
||||
* behavior at runtime (0 = new state machine, 1 = legacy always-0xF3). */
|
||||
int sio_get_legacy_cfg(void);
|
||||
void sio_set_legacy_cfg(int v);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -6297,21 +6297,6 @@ static void handle_sio_trace(int id, const char *json)
|
||||
send_fmt("]}\n");
|
||||
}
|
||||
|
||||
/* Live get/set of the pad config-SM mode, for A/B testing the LEGACY Tomba
|
||||
* Hybrid compatibility path (normally driven per-game by [controller]
|
||||
* legacy_pad_config; see sio.c g_pad_legacy_cfg for the full story).
|
||||
* {"cmd":"pad_cfg"} -> report current mode
|
||||
* {"cmd":"pad_cfg","set":1} -> legacy pre-98aa688 "always 0xF3" config
|
||||
* {"cmd":"pad_cfg","set":0} -> modern DualShock config state machine (default) */
|
||||
static void handle_pad_cfg(int id, const char *json)
|
||||
{
|
||||
int set = json_get_int(json, "set", -1);
|
||||
if (set >= 0) sio_set_legacy_cfg(set);
|
||||
int mode = sio_get_legacy_cfg();
|
||||
send_fmt("{\"id\":%d,\"ok\":true,\"legacy_cfg\":%d,\"mode\":\"%s\"}\n",
|
||||
id, mode, mode ? "legacy-0xF3" : "new-state-machine");
|
||||
}
|
||||
|
||||
static void handle_sio_trace_window(int id, const char *json)
|
||||
{
|
||||
int seq = json_get_int(json, "seq", -1);
|
||||
@@ -12372,7 +12357,6 @@ static const CmdEntry s_commands[] = {
|
||||
{ "chain_trace", handle_chain_trace },
|
||||
{ "sio_trace", handle_sio_trace },
|
||||
{ "sio_trace_window", handle_sio_trace_window },
|
||||
{ "pad_cfg", handle_pad_cfg },
|
||||
{ "sio_pc_trace", handle_sio_pc_trace },
|
||||
{ "sio_pc_window", handle_sio_pc_window },
|
||||
{ "sio_ctrl_reg_trace", handle_sio_ctrl_reg_trace },
|
||||
|
||||
+25
-23
@@ -2671,10 +2671,10 @@ static void apply_input_override_to_sio(int override_word) {
|
||||
st[2] != 0x80 || st[3] != 0x80);
|
||||
const bool dpad_live = ((uint16_t)~w & 0x00F0u) != 0; /* up/right/down/left */
|
||||
|
||||
int mode;
|
||||
if (p.kind != 0) mode = p.mode;
|
||||
else if (dev_any_input_enabled()) mode = (int)PSXRecompV4::PAD_MODE_HYBRID;
|
||||
else mode = (int)PSXRecompV4::PAD_MODE_DIGITAL;
|
||||
/* Debug injection follows the game's resolved mode even when P1 has no
|
||||
* assigned device. This keeps dev-any-input from manufacturing Hybrid for
|
||||
* a title that deliberately exposes only Analog / D-Pad. */
|
||||
const int mode = p.mode;
|
||||
|
||||
int eff_analog;
|
||||
if (mode == (int)PSXRecompV4::PAD_MODE_DIGITAL) {
|
||||
@@ -2712,15 +2712,11 @@ static int capture_pad_slot(int s, PsxNetPad* out) {
|
||||
* state gates how the left stick is read for BOTH the button word and the
|
||||
* analog axes below. An assigned device keeps its configured mode (a
|
||||
* launcher-selected analog DualShock stays analog, so its input path / SIO
|
||||
* handshake cadence is preserved exactly). A P1 with no assigned device but
|
||||
* dev-any-input on presents as HYBRID — boots analog like a DualShock and
|
||||
* auto-drops to digital on the d-pad — so any plugged controller and the
|
||||
* keyboard both navigate. The hybrid latch reads raw device state, so it is
|
||||
* safe to resolve here before the button word is built. */
|
||||
int mode;
|
||||
if (p.kind != 0) mode = p.mode;
|
||||
else if (dev_here) mode = (int)PSXRecompV4::PAD_MODE_HYBRID;
|
||||
else mode = (int)PSXRecompV4::PAD_MODE_DIGITAL;
|
||||
* handshake cadence is preserved exactly). A P1 with no assigned device
|
||||
* keeps the game's resolved mode while dev-any-input merges the keyboard and
|
||||
* all connected controllers. This is important for games that deliberately
|
||||
* do not support Hybrid. */
|
||||
const int mode = p.mode;
|
||||
int eff_analog;
|
||||
if (mode == PSXRecompV4::PAD_MODE_DIGITAL) {
|
||||
eff_analog = 0;
|
||||
@@ -2860,10 +2856,7 @@ static void capture_override_pad(int override_word, PsxNetPad* out) {
|
||||
st[2] != 0x80 || st[3] != 0x80);
|
||||
const bool dpad_live = ((uint16_t)~w & 0x00F0u) != 0;
|
||||
|
||||
int mode;
|
||||
if (p.kind != 0) mode = p.mode;
|
||||
else if (dev_any_input_enabled()) mode = (int)PSXRecompV4::PAD_MODE_HYBRID;
|
||||
else mode = (int)PSXRecompV4::PAD_MODE_DIGITAL;
|
||||
const int mode = p.mode;
|
||||
|
||||
int eff_analog;
|
||||
if (mode == (int)PSXRecompV4::PAD_MODE_DIGITAL) {
|
||||
@@ -4952,12 +4945,6 @@ int main(int argc, char** argv) {
|
||||
ctrl_lock_mode = gc.runtime.controller_lock_mode;
|
||||
ctrl_lock_device = gc.runtime.controller_lock_device;
|
||||
if (gc.runtime.has_deadzone) resolved_deadzone = gc.runtime.deadzone;
|
||||
/* LEGACY per-game pad-config opt-in (default modern). Only Tomba sets
|
||||
* it, so its launcher Hybrid mode's analog<->digital flip doesn't make
|
||||
* libpad manufacture a 1-frame "pad unplugged". sio_init() does not
|
||||
* touch this flag, so applying it here (config-load time) is stable.
|
||||
* Full history + removal plan: psxrecomp sio.c g_pad_legacy_cfg. */
|
||||
sio_set_legacy_cfg(gc.runtime.legacy_pad_config ? 1 : 0);
|
||||
{ const char *e = std::getenv("PSX_GL_FORCE_CPU_PRESENT");
|
||||
if (e && e[0] && e[0] != '0') g_gl_fbo_present = 0; }
|
||||
game_entry_pc = gc.entry_pc;
|
||||
@@ -5308,6 +5295,21 @@ int main(int argc, char** argv) {
|
||||
p1_mode = ctrl_locked_p1_mode;
|
||||
p2_mode = ctrl_locked_p2_mode;
|
||||
}
|
||||
/* allow_hybrid=false removes Hybrid from the game's supported controller
|
||||
* modes. Clamp an old persisted Hybrid value here as well as hiding it in
|
||||
* recomp-ui, so launcher-less builds cannot revive an unsupported mode.
|
||||
* Prefer each port's game-declared default; malformed/legacy configs that
|
||||
* also default to Hybrid fall back to Analog, matching recomp-ui. */
|
||||
if (!ctrl_allow_hybrid) {
|
||||
const int fallback_p1 =
|
||||
ctrl_locked_p1_mode == PSXRecompV4::PAD_MODE_HYBRID
|
||||
? PSXRecompV4::PAD_MODE_ANALOG : ctrl_locked_p1_mode;
|
||||
const int fallback_p2 =
|
||||
ctrl_locked_p2_mode == PSXRecompV4::PAD_MODE_HYBRID
|
||||
? PSXRecompV4::PAD_MODE_ANALOG : ctrl_locked_p2_mode;
|
||||
if (p1_mode == PSXRecompV4::PAD_MODE_HYBRID) p1_mode = fallback_p1;
|
||||
if (p2_mode == PSXRecompV4::PAD_MODE_HYBRID) p2_mode = fallback_p2;
|
||||
}
|
||||
|
||||
/* A game may migrate Skip FMVs from generic Settings into its mod catalog.
|
||||
* Clamp stale settings before seeding recomp-ui; an enabled activation
|
||||
|
||||
+5
-100
@@ -686,68 +686,6 @@ void sio_get_pad_sticks(int slot, uint8_t out[4]) {
|
||||
out[2] = pad_stick[slot][2]; out[3] = pad_stick[slot][3];
|
||||
}
|
||||
|
||||
/* ── LEGACY pad-config compatibility (Tomba "Hybrid" controller) ─────────────
|
||||
*
|
||||
* Why this exists, and why it is explicitly LEGACY:
|
||||
*
|
||||
* This is the descendant of our FIRST controller implementation. It was built
|
||||
* for Tomba, to reproduce the seamless analog/digital feel of Tomba: Special
|
||||
* Edition — the launcher "Hybrid" mode flips the emulated pad's reported TYPE
|
||||
* between digital (poll id 0x41) and DualShock/analog (poll id 0x73) as the
|
||||
* player moves between the d-pad and the stick. In that first implementation
|
||||
* the SIO pad answered the DualShock config-mode commands trivially (it always
|
||||
* reported the config id 0xF3), and Tomba's Hybrid flip worked.
|
||||
*
|
||||
* We then matured the pad against Mega Man X6. MMX6's libpad probes the pad
|
||||
* type via config mode (01 43 00 00 ...) BEFORE it ever polls, and the trivial
|
||||
* "always 0xF3" answer WEDGED it: it looped the probe forever, never reached
|
||||
* the 0x42 poll, and had no input. The fix (commit 98aa688) was a REAL
|
||||
* DualShock config-mode state machine — report 0xF3 only while actually in
|
||||
* config, track 0x43 enter/exit, answer the capability queries (0x45/0x46/
|
||||
* 0x47/0x4C) like the real pad. That "modern" SM is the correct behaviour, is
|
||||
* what MMX6 and every other title needs, and is the default.
|
||||
*
|
||||
* But post-MMX6, under the modern SM, Tomba's Hybrid flip regressed. Any type
|
||||
* change makes libpad re-run findpad / re-detect the pad; under the modern SM
|
||||
* that re-detect manufactures a one-frame "pad unplugged" (buf[0] = 0xFF).
|
||||
* Tomba reads it as a controller disconnect and unpauses the menu / drops
|
||||
* input; MMX6 reads the held direction as released-then-re-pressed and fires a
|
||||
* phantom dash. We could NOT, with the modern SM, keep the flip benign. Rather
|
||||
* than block Tomba's Hybrid feature, we kept the original behaviour available
|
||||
* as a per-game opt-in — this flag.
|
||||
*
|
||||
* What the flag does:
|
||||
* g_pad_legacy_cfg == 0 (default) -> modern DualShock config state machine.
|
||||
* Required by MMX6; correct for every title.
|
||||
* g_pad_legacy_cfg != 0 -> the pre-98aa688 behaviour: config commands
|
||||
* always answer the config id 0xF3, with no
|
||||
* enter/exit tracking. Tomba's libpad was
|
||||
* written against exactly this, so its Hybrid
|
||||
* flip re-detect is benign.
|
||||
*
|
||||
* Driven per-game by [controller] legacy_pad_config in game.toml (applied via
|
||||
* sio_set_legacy_cfg() at boot). ONLY Tomba opts in. Because the default is 0,
|
||||
* the modern path in pad_process_byte() below is byte-for-byte unchanged when
|
||||
* the flag is off — no other title is affected. The `pad_cfg` debug command can
|
||||
* also flip it live for A/B testing.
|
||||
*
|
||||
* THIS IS LEGACY — remove it once the behavioural mechanism is right. A real
|
||||
* DualShock tolerates unlimited analog-button presses (type changes) with no
|
||||
* disconnect, which proves the Hybrid flip CAN be benign under a correct state
|
||||
* machine for every game, with no per-game compatibility branch. When that
|
||||
* findpad/re-detect refactor lands, DELETE this whole legacy feature set — this
|
||||
* flag, the g_pad_legacy_cfg-gated branches in pad_process_byte(), the
|
||||
* legacy_pad_config config field, and the per-game game.toml opt-in — and let
|
||||
* Tomba ride the modern SM like everything else. */
|
||||
volatile int g_pad_legacy_cfg = 0;
|
||||
int sio_get_legacy_cfg(void) { return g_pad_legacy_cfg; }
|
||||
void sio_set_legacy_cfg(int v) {
|
||||
g_pad_legacy_cfg = v ? 1 : 0;
|
||||
/* Clear any in-flight config latch so a mid-session toggle can't carry a
|
||||
* stale 0xF3/8-byte poll into the other mode's dispatch. */
|
||||
pad_in_config[0] = pad_in_config[1] = 0;
|
||||
}
|
||||
|
||||
static void pad_process_byte(uint8_t tx_byte) {
|
||||
/* Apply any pending host type change (the emulated analog button) ONLY while
|
||||
* the bus is idle and the pad is not in config mode. This guarantees the
|
||||
@@ -817,15 +755,7 @@ static void pad_process_byte(uint8_t tx_byte) {
|
||||
* PAD_SEND_RESPONSE so it takes effect after this transaction. */
|
||||
const uint16_t btn = pad_buttons[selected_slot];
|
||||
pad_response[1] = 0x5A;
|
||||
if (g_pad_legacy_cfg) {
|
||||
/* LEGACY (pre-98aa688): always config ID 0xF3, zero frame, no
|
||||
* enter/exit tracking. */
|
||||
pad_response[0] = 0xF3;
|
||||
pad_response[2] = 0x00; pad_response[3] = 0x00;
|
||||
pad_response[4] = 0x00; pad_response[5] = 0x00;
|
||||
pad_response[6] = 0x00; pad_response[7] = 0x00;
|
||||
pad_response_len = 8;
|
||||
} else if (!pad_in_config[selected_slot]) {
|
||||
if (!pad_in_config[selected_slot]) {
|
||||
/* ENTER attempt (normal mode): a real DualShock transmits the LIVE
|
||||
* poll frame here — identical framing to 0x42 (dualshock.cpp:471-490)
|
||||
* — and only latches config entry from the 0x01 data byte AFTERWARD.
|
||||
@@ -857,32 +787,7 @@ static void pad_process_byte(uint8_t tx_byte) {
|
||||
pad_state = PAD_SEND_RESPONSE;
|
||||
sio_rx_data = pad_response[0];
|
||||
sio_stat |= SIO_STAT_ACK;
|
||||
} else if (ds && g_pad_legacy_cfg &&
|
||||
(tx_byte == 0x45 || tx_byte == 0x46 || tx_byte == 0x47 ||
|
||||
tx_byte == 0x4C || tx_byte == 0x4D)) {
|
||||
/* LEGACY config answers (pre-98aa688): canned 0xF3 responses given
|
||||
* UNCONDITIONALLY (no config-mode gating). 0x44/0x4F had no handler
|
||||
* then, so they fall through to the hi-z "no response" else below. */
|
||||
static const uint8_t r_45[8] = { 0xF3,0x5A,0x03,0x02,0x01,0x02,0x01,0x00 };
|
||||
static const uint8_t r_46[8] = { 0xF3,0x5A,0x00,0x00,0x01,0x02,0x00,0x0A };
|
||||
static const uint8_t r_47[8] = { 0xF3,0x5A,0x00,0x00,0x02,0x00,0x01,0x00 };
|
||||
static const uint8_t r_4c[8] = { 0xF3,0x5A,0x00,0x00,0x00,0x04,0x00,0x00 };
|
||||
static const uint8_t r_4d[8] = { 0xF3,0x5A,0x00,0x00,0x00,0x00,0x00,0x00 };
|
||||
const uint8_t *r = r_4d;
|
||||
if (tx_byte == 0x45) r = r_45;
|
||||
else if (tx_byte == 0x46) r = r_46;
|
||||
else if (tx_byte == 0x47) r = r_47;
|
||||
else if (tx_byte == 0x4C) r = r_4c;
|
||||
memcpy(pad_response, r, 8);
|
||||
/* 0x45 status byte must report the LIVE analog mode, not a fixed
|
||||
* analog-on (dualshock.cpp:743) — see fix below for the modern path. */
|
||||
if (tx_byte == 0x45)
|
||||
pad_response[3] = pad_analog[selected_slot] ? 0x01 : 0x00;
|
||||
pad_response_len = 8;
|
||||
pad_state = PAD_SEND_RESPONSE;
|
||||
sio_rx_data = pad_response[0];
|
||||
sio_stat |= SIO_STAT_ACK;
|
||||
} else if (ds && !g_pad_legacy_cfg && pad_in_config[selected_slot] &&
|
||||
} else if (ds && pad_in_config[selected_slot] &&
|
||||
(tx_byte == 0x44 || tx_byte == 0x45 || tx_byte == 0x46 ||
|
||||
tx_byte == 0x47 || tx_byte == 0x4C || tx_byte == 0x4D ||
|
||||
tx_byte == 0x4F)) {
|
||||
@@ -929,7 +834,7 @@ static void pad_process_byte(uint8_t tx_byte) {
|
||||
* exit(0x00) arrives paired with response index 2. Latch the new config
|
||||
* state; it takes effect from the next transaction (the ID byte already
|
||||
* reported the mode that was current at the start of this one). */
|
||||
if (!g_pad_legacy_cfg && pad_current_cmd == 0x43 && pad_response_idx == 2)
|
||||
if (pad_current_cmd == 0x43 && pad_response_idx == 2)
|
||||
pad_in_config[selected_slot] = (tx_byte == 0x01) ? 1 : 0;
|
||||
/* 0x44 set-mode (game owns the analog/digital mode): the mode byte rides
|
||||
* in the same slot as 0x43's enter/exit flag (data position 3). 0x01 =>
|
||||
@@ -937,14 +842,14 @@ static void pad_process_byte(uint8_t tx_byte) {
|
||||
* coherent — the type the game just selected is the type it then polls,
|
||||
* instead of the host hybrid silently winning. Drop any stale host
|
||||
* request so it can't immediately undo the game's choice. */
|
||||
if (!g_pad_legacy_cfg && pad_current_cmd == 0x44 && pad_response_idx == 2) {
|
||||
if (pad_current_cmd == 0x44 && pad_response_idx == 2) {
|
||||
pad_analog[selected_slot] = (tx_byte == 0x01) ? 1 : 0;
|
||||
pad_type_req[selected_slot] = -1;
|
||||
}
|
||||
/* 0x44 lock byte (data position 4, the byte after the mode byte): 0x03 =>
|
||||
* lock analog mode, 0x02 => unlock (dualshock.cpp:714-725). A locked slot
|
||||
* ignores the host hybrid auto-flip (see analog_mode_locked). */
|
||||
if (!g_pad_legacy_cfg && pad_current_cmd == 0x44 && pad_response_idx == 3) {
|
||||
if (pad_current_cmd == 0x44 && pad_response_idx == 3) {
|
||||
if (tx_byte == 0x03) analog_mode_locked[selected_slot] = 1;
|
||||
else if (tx_byte == 0x02) analog_mode_locked[selected_slot] = 0;
|
||||
}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Phantom-input A/B instrument driver: get/set the pad config-SM mode live.
|
||||
|
||||
Usage:
|
||||
python padcfg.py # report current mode
|
||||
python padcfg.py 1 # legacy pre-98aa688 "always 0xF3" config
|
||||
python padcfg.py 0 # new config state machine (shipping)
|
||||
Optional: PORT as 2nd arg (default 4470, Tomba dev build).
|
||||
"""
|
||||
import socket, json, sys
|
||||
|
||||
port = 4470
|
||||
setv = None
|
||||
if len(sys.argv) > 1 and sys.argv[1] != "":
|
||||
setv = int(sys.argv[1])
|
||||
if len(sys.argv) > 2:
|
||||
port = int(sys.argv[2])
|
||||
|
||||
cmd = {"cmd": "pad_cfg"}
|
||||
if setv is not None:
|
||||
cmd["set"] = setv
|
||||
|
||||
try:
|
||||
s = socket.create_connection(("127.0.0.1", port), 3)
|
||||
s.sendall((json.dumps(cmd) + "\n").encode())
|
||||
print(s.recv(65536).decode().strip())
|
||||
except Exception as e:
|
||||
print("debug server not up yet (expected until in-game):", e)
|
||||
Reference in New Issue
Block a user