Home Artists Posts Import Register

Content

With CleanROM 2.1.0.0 freshly released and full PS4 Remote Play support finally being a thing on the XD+ I figured screw it, invest some extra time, and document how the whole thing came together from start to finish.

This post will be split into several chapters (for a lack of better words), describing the idea, issues and steps taken to solve said issues in chronological order.

Let us begin.

The idea

With Sony's recent move of making the PS4 Remote Play app (semi-)openly available via the Play Store, a user by the name of kuraudo1996 left a comment on this Patreon page, asking if it would be possible to add DualShock 4 support to the XD+'s built-in gamepad so that people could stream their PS4 games to their XD+ without having to rely on external gamepads.

While theoretically and practically possible, this endeavor brought with it its own set of problems, which first had to be solved.

The "rocker" / "adc_js" driver

This is the driver that takes care of capturing the XD+'s gamepad input and turning it into either PS3 (DualShock 3), Xbox 360 (XInput) or CF (touchscreen) input data.

There are two variations of this driver.

A closed source one and a open source one.

Making changes to the open source one is no problem and fairly easy to do, however, given the fact it lacks the CF (touchscreen) related code, we'd be losing the XD+'s key feature, the touchscreen mapper.

Given how popular said feature is with the userbase it was clear that we couldn't go that route. Trading in one feature for another would be a no-go.

We could of done two separate builds, letting the user decide what feature they'd want over the other, but I didn't feel right splitting the userbase in half.

Thus we were now stuck with a theoretically possible idea, and no easy way of achieving it without repercussions.

The hard way

I said there's no easy way. But there sure was a hard one.

What if we took the closed source driver... analyzed its machine code (assembly) and manually patched in the required changes to make this happen?

After all we had a (inferior) open source version of the driver from which we could reference certain code segments. How hard could it be?

That was my thought at the time, so I started digging, sent WIP test builds out, and eventually succeeded, but let's take it one step at a time.

The required changes

To make the built-in PS3 gamepad driver appear and act as if it was a DualShock 4 gamepad, there were quite a few changes that needed to be made.

These were the ones I figured were necessary:

  • We needed to change the device name to match a real DualShock 4 gamepad
  • We needed to change the device ID to match a real DualShock 4 gamepad
  • We needed to patch the device capabilities descriptor to include the shoulder button axis 3 & 4 (that a DualShock 3 doesn't have, but a DualShock 4 does)
  • We needed to patch the button keycodes to match a real DualShock 4 gamepad
  • We needed to patch the axis list to include the shoulder button axis 3 & 4 (that a DualShock 3 doesn't have, but a DualShock 4 does)
  • We needed to add digital directional pad button mappings to the DualShock 4 keylayout (I will explain why that is on the actual step)

Changing the device name

This step was, by far, the easiest of them all.

I merely had to override the "PLAYSTATION(R)3" string to "DualShock 4" and we were done.

Nothing to see here guys, move along...

Changing the device ID

The PS3 (DualShock 3) gamepad mode simulates a device ID 0x268, but for the device to register as a PS4 (DualShock 4) gamepad we had to change things around to 0x5c4.

Just like the name change this was trivial to do.

I changed a single ARM64 operation in the driver's machine code and we were set.

Setting the device capabilities

When the Linux kernel detects a new input device it will assign a driver to it and wait for said driver to report the device capabilities.

It's essentially a fancy way of saying "Hey, what can you do?"

In our case, the driver needs to report what buttons and analog axis are available on the simulated gamepad.

The real work here was to add two additional analog axis to the report, as the shoulder buttons on a PS3 (DualShock 3) gamepad are digital, while on a PS4 (DualShock 4) they are analog.

Luckily enough though the PS3 (DualShock 3) driver already had two dummy axis we could rewrite / hijack for this.

As you can see on this screenshot there's already a 0x30 and 0x31 axis being reported (which is never used).

Perfect cannon fodder for us to rewrite into a 0x3 (left trigger) and 0x4 (right trigger) analog axis!

Changing the button keycodes

To match the official PS4 (DualShock 4) button mapping we had to change the PS3 (DualShock 3) button keycodes to match those of the newer generation gamepad.

Using the open source driver as a reference, I found that the structure containing the keycodes was called "gamekeys".

Armed with that piece of info I decided to go digging in the machine code, which (luckily enough) still had its debug information stored inside the binary.

Thanks to this little oversight on GPD's behalf, I could literally just open up the driver's name table and double-click on the equally named object to bring me to the section of the binary that contained the binary-encoded structure containing the keycode mappings.

Using some more reference code taken from the open source driver I managed to pin-point the sections that needed changing.

I've marked the first two keycodes on the screenshot to make it easier for you, the reader, to follow.

Using an off-screen list of PS3 (DualShock 3) and PS4 (DualShock 4) keycodes I slowly worked my way through the structure, patching each of the older generation keycodes up to match their newer counterpart.

This took care of all the digital buttons, more or less, leaving...

Changing the axis list

With the digital buttons out of the way, we had one more spot to patch to make the analog shoulder buttons work as expected.

In a previous step we patched the device capabilities report to include the new shoulder button axis 3 & 4, but to make these work properly we also had to patch them in the axis list.

Armed with the open source version of the driver as a reference, I once again identified the structure name and dove right in.

The name of the structure was "ps3_axis", and once again I used the name list in the binary to find its location inside the closed source driver.

Using some more reference code from the open source driver we were quick to find our old friends, the unused 0x30 and 0x31 analog axis...

Which we promptly patched into a 3 & 4 axis to match the PS4 (DualShock 4) shoulder axis IDs.

This part kept me going for a while...
You see, I didn't know at the time that this modification was necessary, and I was scratching my head wondering why the shoulder button axis wasn't being triggered properly.
I had to sleep on this and ended up face-palming for not seeing this earlier when realization finally struck me.
Things always seem so easy when all the work is done and the actual changes are nicely documented, but back when I worked this thing out it wasn't as obvious.

Getting the directional pad running

Everything was great, except for the fact that the directional pad wasn't working.

Just like the L2/R2 shoulder triggers, the directional pad had changed from a set of 4 digital keys to 2 analog axis on the PS4 (DualShock 4) gamepad.

Sadly though we had run out of dummy axis to hijack, and the driver is tightly knit with few code-gaps I could utilize to add additional axis configurations.

As such, a desperate plan was put into motion...

Instead of hacking the driver further (employing a set of nasty tricks like code-gap generation, structure moves, etc.) I decided to patch the 4 PS4 (DualShock 4) keylayout files to add XD+ specific alternate button mappings for the directional pad keycodes.

While this strays from the official PS4 (DualShock 4) standard, it seems to work just fine.

I might be revisiting this step at a later point though as I'm not a big fan of workarounds.

The proper way to do this would be to somehow patch in these additional 2 analog axis into the driver by moving the structures into a big enough (found or generated) code-gap.

At that point we'd be able to remove the keylayout file modifications.

The summary of things

We've reached the end of this summary and earned ourselves a fully working PS4 (DualShock 4) gamepad mode for our built-in XD+ gamepad, unlocking a truly portable PS4 Remote Play experience as a (very welcome) side-effect.

Tell me what you guys think about this style of newsletter posts in the comments and whether you'd like more behind-the-scenes development focused posts like these.

Until next time!

- Black-Seraph

Files

Comments

Peter

Amazing work and your skills are supreme. I do ebjoy this style of post but if it takes away from your development time I can live without them.