Cxbx-reloaded: Remove hacks from `XGetDeviceChanges`

Created on 29 Aug 2017  ·  10Comments  ·  Source: Cxbx-Reloaded/Cxbx-Reloaded

A recent Pull Request (#687) added a title-specific hack to XGetDeviceChanges, which resulted in state-booting changing to state-working.

Instead of add hacks to support more titles, more fundamental research most be done, so a real fix can be made, allowing the removal of these hacks. It's fairly probable more titles will benefit from this.

bug high-priority input

All 10 comments

The key problem is that we still have no idea why this hack is needed.

Unpatching this function prevents some titles from detecting controllers, patching this function fixes said controller issues but breaks JSRF during early startup. If we wish to HLE controller devices, this function must indeed be patched.

After spending weeks on the issue, I settled with the hack and I plan to completely unpatch XINPUT and LLE emulate the USB devices later on, so then input shouldn't be a problem anymore. My experimental NV2A branch contains good prep-work for this (DPC routines, some form of interrupt handling), PCI emulation and OHCI emulation are the required next steps, after those, actual gamepad devices can be emulated by hooking up virtual USB devices to the OHCI bus.

One reason XGetDeviceChanges doesn't work (well), is because of this line, which accesses DeviceType->CurrentConnected (DeviceType being a PXPP_DEVICE_TYPE). It's possible this pointer isn't initialized properly, resulting in accesses to random memory adresses...

Although this is possible (and should be checked for) in practice, I have never seen this happen, and the crash never happens within this function, but some time after it returns, much later in execution but still before anything displays onscreen, so this, while potentially a problem, is not this problem

JSRF executes the following instruction..

.text:001669D7 call _XGetDeviceChanges@12 ; XGetDeviceChanges(x,x,x)
.text:001669DC test eax, eax
.text:001669DE jnz loc_166B0D

.text:00166B0D loc_166B0D:
.text:00166B0D mov eax, 80004005h
.text:00166B12 pop edi
.text:00166B13 pop esi
.text:00166B14 pop ebx
.text:00166B15 mov esp, ebp
.text:00166B17 pop ebp
.text:00166B18 retn 14h

Modified 00166B0D to a trap, executes XGetDeviceChanges function after Received Breakpoint Exception (int 3) message appears.

.text:001669D7 call _XGetDeviceChanges@12 ; XGetDeviceChanges(x,x,x)
.text:001669DC test eax, eax
.text:001669DE jnz loc_166B0D

.text:00166B0D loc_166B0D:
.text:00166B0D int 3
---------------------------
Cxbx-Reloaded
---------------------------
Received Breakpoint Exception (int 3) @ EIP := 0x00166B0D(=XRegisterThreadNotifyRoutine+0x1ec9b)

  Press Abort to terminate emulation.
  Press Retry to debug.
  Press Ignore to continue emulation.
---------------------------
中止(A)   再試行(R)   無視(I)
---------------------------

In my reasoning, implementation of the XGetDeviceChanges function is no problem. Other functions will cause a crash.

Okay, the REAL issue with certain titles having no input from controller is just because of XGetDevices patch is not detected properly or simply missing. I changed the code, XGetDeviceChanges, to

if (DeviceType->ChangeConnected == 0) {
    *pdwInsertions = 0;
    *pdwRemovals = 0;
    ret = FALSE;
}

Which makes it accurate base on reverse engineered XGetDeviceChanges function. It is functional just fine with JSRF, even with Turok Evolution. However the rest of the function is little bit confusing to me. I can create a pull request for more accurate fix.

Edit: Here's proposal change to XGetDeviceChanges. It's under "Fix XGetDeviceChanges method" commit.

I went down this path while looking into this issue: Some titles call XGetDeviceChanges before calling XGetDevices, and then assume no controllers are connected, hence why XGetDeviceChanges was modified to return 1 new device on the first call.

JSRF breaks when XGetDeviceChanges returns anything other than false/no new devices, however some titles detect no input unless XGetDeviceChanges returns TRUE/1 device inserted on the first iteration.

AeroX2 and Lego Star Wars are effected by this, and I'm sure there are more.

The true HLE solution would be to unpatch XInput functionality, and instead patch the XID driver functions to emulate the USB gamepad.

Although if going to this depth, you might as well go all the way and LLE input completely.

JSRF breaks when XGetDeviceChanges returns anything other than false/no new devices, however some titles detect no input unless XGetDeviceChanges returns TRUE/1 device inserted on the first iteration.

How so? XGetDevices gave the device of 1 is detected. When XGetDeviceChanges was called, CurrentConnected value has the value of 1 even if ChangeConnected has 0. The original method is just force adding controller 4 times.

Lego Star Wars does not have XGetDevices patch, it is showing 0 in my HLE Cache. Hence the reason of no controller input. I believe we need to fix/add OOVPA for XGetDevices in order for Lego Star Wars, 5849 XDK, instead of making hacks.

I'll investigate this little bit more, just to be sure XGetDevices doesn't come with certain 5849 titles.

I strongly believe it is wrong to patch any of the XInput device functionality, and instead either intercept the XID functions (for HLE) or LLE emulate the whole USB hardware.

My reasoning is that games are able to install and register their own device drivers with XID and if we ever hope to support other XID devices (memory units, DVD dongle, light guns, Steel Battalion controller, etc) we will need XID level emulation.

If you can fix the current XInput HLE without further hacks and without breaking other titles, that's great, please do!

But it's still not the right way to go about it long term.

Note that in my experimental NV2A branch, we have almost all the prerequisites required for XID LLE, so in reality, we are probably not too far away from being able to do this properly.

Honestly, I do agree with you.

I made a 2nd commit to preserve device is not detected to be insert instead of force failure. Problem is, I am currently having issue with Lego Star Wars 1 & 2 titles and Star Wars KoToR 2 atm... I'm not sure why.

🏳️ 😞 🏳️
I tried, it didn't work out for Lego Star Wars and JSRF without hacks.

Was this page helpful?
0 / 5 - 0 ratings