dualsense: possibly fix weird vibrations
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
./lact.nix
|
||||
./vr.nix
|
||||
./forza-trigger
|
||||
./dualsense-attenuation.nix
|
||||
|
||||
inputs.impermanence.nixosModules.impermanence
|
||||
];
|
||||
@@ -173,4 +174,9 @@
|
||||
|
||||
# PS5 DualSense adaptive triggers in Forza Horizon 4 / 5.
|
||||
services.forzaTrigger.enable = true;
|
||||
|
||||
# PS5 DualSense LRA whine fix: cap firmware-level haptic amplitude so the
|
||||
# voice-coil actuators never hit their audible-buzz regime under heavy
|
||||
# rumble. Independent of the forza-trigger adaptive trigger path.
|
||||
services.dualsenseAttenuation.enable = true;
|
||||
}
|
||||
|
||||
93
hosts/yarn/dualsense-attenuation.nix
Normal file
93
hosts/yarn/dualsense-attenuation.nix
Normal file
@@ -0,0 +1,93 @@
|
||||
# DualSense rumble/trigger firmware-level attenuation.
|
||||
#
|
||||
# The PS5 controller's haptic actuators are linear resonant actuators (LRAs) —
|
||||
# voice coils, not ERM rotors. When driven near max amplitude they emit an
|
||||
# audible high-pitched whine in addition to the intended rumble. This is a
|
||||
# hardware property of the actuator, not a kernel or Steam Input bug, and
|
||||
# can't be fixed in any rumble path that talks to the LRAs at full strength.
|
||||
#
|
||||
# Sony exposes a firmware knob ("rumble emulation amplitude modifier", in
|
||||
# DS_OUTPUT report 0x05/0x31, gated by valid_flag2 bit RUMBLE_EMULATION_SELECT)
|
||||
# that clamps haptic / trigger amplitude before the actuator is driven. This
|
||||
# module sends that report once on plug-in via dualsensectl. The setting
|
||||
# lives in controller RAM until the next power-cycle (USB unplug or BT
|
||||
# disconnect-with-power-off), so re-applying on every udev `add` covers
|
||||
# every reconnect.
|
||||
#
|
||||
# Coexists with Steam Input's rumble path: Steam writes rumble in the same
|
||||
# output report, but only sets COMPATIBLE_VIBRATION / HAPTICS_SELECT in
|
||||
# valid_flag0 — not RUMBLE_EMULATION_SELECT — so its writes don't reset the
|
||||
# attenuation. Verified live with Steam (gamepadui) and forza-trigger both
|
||||
# holding hidraw concurrently.
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.services.dualsenseAttenuation;
|
||||
|
||||
applyScript = pkgs.writeShellScript "dualsense-apply-attenuation" ''
|
||||
set -eu
|
||||
# Retry briefly: the hidraw node exists by udev `add`, but the device
|
||||
# may still be settling its initial HID descriptor exchange. dualsensectl
|
||||
# needs to read the firmware report before it can write attenuation.
|
||||
for _ in 1 2 3 4 5 6 7 8 9 10; do
|
||||
if ${pkgs.dualsensectl}/bin/dualsensectl -l 2>/dev/null | grep -q ":"; then
|
||||
exec ${pkgs.dualsensectl}/bin/dualsensectl attenuation \
|
||||
${toString cfg.rumble} ${toString cfg.trigger}
|
||||
fi
|
||||
sleep 0.2
|
||||
done
|
||||
echo "no DualSense detected; nothing to attenuate" >&2
|
||||
exit 0
|
||||
'';
|
||||
in
|
||||
{
|
||||
options.services.dualsenseAttenuation = {
|
||||
enable = lib.mkEnableOption "Apply DualSense haptic attenuation on plug-in";
|
||||
|
||||
rumble = lib.mkOption {
|
||||
type = lib.types.ints.between 0 7;
|
||||
default = 3;
|
||||
description = ''
|
||||
Rumble (LRA) attenuation, 0-7. Higher = weaker. 3 keeps the LRAs
|
||||
below their audible-whine threshold while leaving rumble clearly
|
||||
perceptible. 0 disables attenuation (full strength).
|
||||
'';
|
||||
};
|
||||
|
||||
trigger = lib.mkOption {
|
||||
type = lib.types.ints.between 0 7;
|
||||
default = 0;
|
||||
description = ''
|
||||
Adaptive trigger attenuation, 0-7. Higher = weaker. 0 leaves
|
||||
trigger feedback untouched — forza-trigger drives the triggers
|
||||
with bounded amplitudes already, so the trigger LRAs don't
|
||||
normally hit the audible regime.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
services.udev.extraRules = ''
|
||||
# DualSense (USB)
|
||||
ACTION=="add", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0ce6", TAG+="systemd", ENV{SYSTEMD_WANTS}+="dualsense-attenuation.service"
|
||||
# DualSense Edge (USB)
|
||||
ACTION=="add", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0df2", TAG+="systemd", ENV{SYSTEMD_WANTS}+="dualsense-attenuation.service"
|
||||
# DualSense (Bluetooth)
|
||||
ACTION=="add", SUBSYSTEM=="hidraw", KERNELS=="*054C:0CE6*", TAG+="systemd", ENV{SYSTEMD_WANTS}+="dualsense-attenuation.service"
|
||||
# DualSense Edge (Bluetooth)
|
||||
ACTION=="add", SUBSYSTEM=="hidraw", KERNELS=="*054C:0DF2*", TAG+="systemd", ENV{SYSTEMD_WANTS}+="dualsense-attenuation.service"
|
||||
'';
|
||||
|
||||
systemd.services.dualsense-attenuation = {
|
||||
description = "Apply DualSense rumble/trigger attenuation in controller firmware";
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
ExecStart = applyScript;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user