[PATCH] HID: playstation: Remap joystick axes to be centered at 0

Siarhei Vishniakou posted 1 patch 2 months, 1 week ago
drivers/hid/hid-playstation.c | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
[PATCH] HID: playstation: Remap joystick axes to be centered at 0
Posted by Siarhei Vishniakou 2 months, 1 week ago
The joystick axes (ABS_X, ABS_Y, ABS_RX, ABS_RY) for PlayStation
gamepads report a neutral state of 128 over HID, with a full range of
[0, 255]. The driver previously mapped this directly, resulting in an
evdev range of [0, 255] with a resting point of 128.

This approach is unconventional for Linux gamepad drivers and has several
drawbacks: it requires userspace applications to be aware of the
non-zero resting state, and it is incompatible with the input
subsystem's 'flat' (deadzone) logic, which assumes a resting point of 0.

This patch remaps the four joystick axes to the conventional signed
8-bit range of [-128, 127], with 0 as the neutral state. This is
accomplished by changing their evdev range in ps_gamepad_create() and
translating the incoming hardware value in the report parsing functions
by subtracting 128.

The analog trigger axes (ABS_Z, ABS_RZ) are handled separately. Their
resting state is 0 (un-pressed), and their hardware range of [0, 255]
is already the conventional representation. They are left unmodified by
this patch.

This makes the joystick behavior consistent with other gamepad drivers
while preserving the standard behavior for the triggers.

Signed-off-by: Siarhei Vishniakou <svv@google.com>
---
 drivers/hid/hid-playstation.c | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/hid/hid-playstation.c b/drivers/hid/hid-playstation.c
index 1468fb11e39d..ca5bca9c2654 100644
--- a/drivers/hid/hid-playstation.c
+++ b/drivers/hid/hid-playstation.c
@@ -718,11 +718,11 @@ static struct input_dev *ps_gamepad_create(struct hid_device *hdev,
 	if (IS_ERR(gamepad))
 		return ERR_CAST(gamepad);
 
-	input_set_abs_params(gamepad, ABS_X, 0, 255, 0, 0);
-	input_set_abs_params(gamepad, ABS_Y, 0, 255, 0, 0);
+	input_set_abs_params(gamepad, ABS_X, -128, 127, 0, 0);
+	input_set_abs_params(gamepad, ABS_Y, -128, 127, 0, 0);
 	input_set_abs_params(gamepad, ABS_Z, 0, 255, 0, 0);
-	input_set_abs_params(gamepad, ABS_RX, 0, 255, 0, 0);
-	input_set_abs_params(gamepad, ABS_RY, 0, 255, 0, 0);
+	input_set_abs_params(gamepad, ABS_RX, -128, 127, 0, 0);
+	input_set_abs_params(gamepad, ABS_RY, -128, 127, 0, 0);
 	input_set_abs_params(gamepad, ABS_RZ, 0, 255, 0, 0);
 
 	input_set_abs_params(gamepad, ABS_HAT0X, -1, 1, 0, 0);
@@ -1349,10 +1349,10 @@ static int dualsense_parse_report(struct ps_device *ps_dev, struct hid_report *r
 		return -1;
 	}
 
-	input_report_abs(ds->gamepad, ABS_X,  ds_report->x);
-	input_report_abs(ds->gamepad, ABS_Y,  ds_report->y);
-	input_report_abs(ds->gamepad, ABS_RX, ds_report->rx);
-	input_report_abs(ds->gamepad, ABS_RY, ds_report->ry);
+	input_report_abs(ds->gamepad, ABS_X,  ds_report->x - 128);
+	input_report_abs(ds->gamepad, ABS_Y,  ds_report->y - 128);
+	input_report_abs(ds->gamepad, ABS_RX, ds_report->rx - 128);
+	input_report_abs(ds->gamepad, ABS_RY, ds_report->ry - 128);
 	input_report_abs(ds->gamepad, ABS_Z,  ds_report->z);
 	input_report_abs(ds->gamepad, ABS_RZ, ds_report->rz);
 
@@ -2272,10 +2272,10 @@ static int dualshock4_parse_report(struct ps_device *ps_dev, struct hid_report *
 		return -1;
 	}
 
-	input_report_abs(ds4->gamepad, ABS_X,  ds4_report->x);
-	input_report_abs(ds4->gamepad, ABS_Y,  ds4_report->y);
-	input_report_abs(ds4->gamepad, ABS_RX, ds4_report->rx);
-	input_report_abs(ds4->gamepad, ABS_RY, ds4_report->ry);
+	input_report_abs(ds4->gamepad, ABS_X,  ds4_report->x - 128);
+	input_report_abs(ds4->gamepad, ABS_Y,  ds4_report->y - 128);
+	input_report_abs(ds4->gamepad, ABS_RX, ds4_report->rx - 128);
+	input_report_abs(ds4->gamepad, ABS_RY, ds4_report->ry - 128);
 	input_report_abs(ds4->gamepad, ABS_Z,  ds4_report->z);
 	input_report_abs(ds4->gamepad, ABS_RZ, ds4_report->rz);
 
-- 
2.51.0.740.g6adb054d12-goog
Re: [PATCH] HID: playstation: Remap joystick axes to be centered at 0
Posted by Jiri Kosina 1 month, 2 weeks ago
On Fri, 10 Oct 2025, Siarhei Vishniakou wrote:

> The joystick axes (ABS_X, ABS_Y, ABS_RX, ABS_RY) for PlayStation
> gamepads report a neutral state of 128 over HID, with a full range of
> [0, 255]. The driver previously mapped this directly, resulting in an
> evdev range of [0, 255] with a resting point of 128.
> 
> This approach is unconventional for Linux gamepad drivers and has several
> drawbacks: it requires userspace applications to be aware of the
> non-zero resting state, and it is incompatible with the input
> subsystem's 'flat' (deadzone) logic, which assumes a resting point of 0.
> 
> This patch remaps the four joystick axes to the conventional signed
> 8-bit range of [-128, 127], with 0 as the neutral state. This is
> accomplished by changing their evdev range in ps_gamepad_create() and
> translating the incoming hardware value in the report parsing functions
> by subtracting 128.
> 
> The analog trigger axes (ABS_Z, ABS_RZ) are handled separately. Their
> resting state is 0 (un-pressed), and their hardware range of [0, 255]
> is already the conventional representation. They are left unmodified by
> this patch.
> 
> This makes the joystick behavior consistent with other gamepad drivers
> while preserving the standard behavior for the triggers.
> 
> Signed-off-by: Siarhei Vishniakou <svv@google.com>

Hmmm ... as I am rather unaware of the existing playstation userspace 
ecosystem -- is there any way how we could now be breaking existing 
playstation-specific userspace assumptions that have already developed 
based on asumptions that we're centered at 128?

Thanks,

-- 
Jiri Kosina
SUSE Labs
Re: [PATCH] HID: playstation: Remap joystick axes to be centered at 0
Posted by Siarhei Vishniakou 1 month, 1 week ago
пт, 31 окт. 2025 г. в 02:00, Jiri Kosina <jikos@kernel.org>:
>
> On Fri, 10 Oct 2025, Siarhei Vishniakou wrote:
>
> > The joystick axes (ABS_X, ABS_Y, ABS_RX, ABS_RY) for PlayStation
> > gamepads report a neutral state of 128 over HID, with a full range of
> > [0, 255]. The driver previously mapped this directly, resulting in an
> > evdev range of [0, 255] with a resting point of 128.
> >
> > This approach is unconventional for Linux gamepad drivers and has several
> > drawbacks: it requires userspace applications to be aware of the
> > non-zero resting state, and it is incompatible with the input
> > subsystem's 'flat' (deadzone) logic, which assumes a resting point of 0.
> >
> > This patch remaps the four joystick axes to the conventional signed
> > 8-bit range of [-128, 127], with 0 as the neutral state. This is
> > accomplished by changing their evdev range in ps_gamepad_create() and
> > translating the incoming hardware value in the report parsing functions
> > by subtracting 128.
> >
> > The analog trigger axes (ABS_Z, ABS_RZ) are handled separately. Their
> > resting state is 0 (un-pressed), and their hardware range of [0, 255]
> > is already the conventional representation. They are left unmodified by
> > this patch.
> >
> > This makes the joystick behavior consistent with other gamepad drivers
> > while preserving the standard behavior for the triggers.
> >
> > Signed-off-by: Siarhei Vishniakou <svv@google.com>
>
> Hmmm ... as I am rather unaware of the existing playstation userspace
> ecosystem -- is there any way how we could now be breaking existing
> playstation-specific userspace assumptions that have already developed
> based on asumptions that we're centered at 128?
>
> Thanks,
>
> --
> Jiri Kosina
> SUSE Labs
>

Thanks Jiri for looking! I chatted with Roderick, and he brought up
similar concerns. Generally, most of the joysticks have the "normal"
ranges with the 0 value at the center. However, I understand that some
user-space apps might have hardcoded some of these Sony-specific
assumptions.

Instead, I will change this patch to provide correct initial
(centered) values of 0x80 when the driver first starts. This is needed
in order to fix our Sony gamepad tests on Android (and will help
everyone else, because now there won't be a stray "bring to center"
event emitted from the gamepad in the beginning). I will follow up
later this week.